#AnThroM Experiment 1: testing the relation between dispositional anthropomorphism and Theory-of-Mind network activation
by Ruud Hortensius and Michaela Kent (University of Glasgow) - June 2019 - …

1. Details

1.1 Data description

Data of the Theory-of-Mind functional localiser and Individual Differences in Anthropomorphism Questionnaire are from five different studies.

Dataset_1: Bangor Imaging Unit; EMBOTS; n=29 (including 1 pilot scan); full dataset and publication: Cross…Hortensius (2019) PTRB.

Dataset_2: Centre for Cognitive NeuroImaging; SHAREDBOTS; n=35 (including 2 pilot scans) publication: Hortensius & Cross, in preparation.

Dataset_3: Centre for Cognitive NeuroImaging; Two studies with the same parameters: n=22 (including 2 pilot scans). Social_Gradient_1; n=10 (pilot experiment) and BOLDlight; n=12.

Dataset_4: Centre for Cognitive NeuroImaging; GAMEBOTS; n=22.

Get info for table S1:

library("tidyverse")

#load own data
DF.dataset1 <- read_tsv(file = "/Volumes/Project0255/dataset_1/participants.tsv")
DF.dataset2 <- read_tsv(file = "/Volumes/Project0255/dataset_2/participants.tsv")
DF.dataset3 <- read_tsv(file = "/Volumes/Project0255/dataset_3/participants.tsv")
DF.dataset4 <- read_tsv(file = "/Volumes/Project0255/dataset_4/participants.tsv")

#combine data
bind_rows(DF.dataset1, DF.dataset2, DF.dataset3,  DF.dataset4, .id = "dataset") %>%
  group_by(dataset) %>% 
  summarise(mean = mean(age), 
            sd = sd(age))
bind_rows(DF.dataset1, DF.dataset2, DF.dataset3,  DF.dataset4, .id = "dataset") %>%
  group_by(dataset, sex) %>% 
  tally()

1.2 Neuroimaging procedure

All participants completed a Theory-of-Mind localiser (Jacoby et al., 2016; Richardson et al. 2018) and an anatomical scan either in the same session or in two seperate sessions. During the localiser participants passively viewed a short 5.6 min animated film (Partly Cloudy). This movie includes scenes depicting pain (e.g. an alligator biting the main character) and events that trigger mentalizing (e.g. the main character revealing its intention). For dataset_3 and dataset_4 a fieldmap was collected as well. At the end of each experiment participants completed the Individual Differences in Anthropomorphism Questionnaire (IDAQ) (Waytz et al., 2010).

  • BOLD:
    Dataset_1: 3x3x3.5mm voxels, 32 slices, repetition time = 2s, echo time = 30ms
    Dataset_2: 3mm isotropic, 37 slices, TR = 2s, TE = 30ms
    Dataset_3: 2mm isotropic, 68 slices, TR = 2s, TE = 26ms
    Dataset_4: 2.75 x 2.75 x 4mm, 32 slices, TR = 2s, TE = 13 and 31ms

  • T1W:
    Dataset_1: 1mm isotropic resolution, TR = 12ms, TE = 3.47 / 5.15 / 6.83 / 8.52 / 10.20ms (SENSE)
    Dataset_2 - 4: 1mm isotropic resolution, TR = 2.3s, TE = 29.6ms (ADNI)

  • Fieldmaps:
    Dataset_1: no, so –use-syn-sdc
    Dataset_2: no, so –use-syn-sdc
    Dataset_3: yes
    Dataset_4: yes

1.3 To do

  • remove Dicoms after BIDS dataset creation
  • run formal analyses (Bayesian)

Note: for the code chunk the language is listed, but all except for r-chunks are executed in the terminal

2. BIDS dataset

2.1 Creating the BIDS dataset

For this you need HeuDiConv Heuristic DICOM Converter.
Based on the tutorial by Franklin Feingold.

Dowload the latest version of Heudiconv (we used 0.6.0.dev1):

docker pull nipy/heudiconv:latest

If on the GRID do:

singularity pull docker://nipy/heudiconv:latest

Create the info file (dataset_2 - 4):

docker run --rm -it -v /Volumes/Project0255/:/base nipy/heudiconv:latest -d /base/dataset_3/sourcedata/sub-{subject}/*.IMA -o /base/dataset_3 -f convertall -s 315 -c none --overwrite

For dataset_1 we first need to convert the .dcm from jpeg-2000 lossless to uncompressed dcm (thanks to Michele Svanera for the code):

python3 convert_all_compressed_dicom.py

Create the info file (dataset_1):

docker run --rm -it -v /Volumes/Project0255/:/base nipy/heudiconv:latest -d /base/dataset_1/sourcedata/sub-{subject}/ses-{session}/*.dcm -o /base/dataset_1 -f convertall -s 129 -ss 01 -c none --overwrite

Get the info file:

cp /Volumes/Project0255/code/.heudiconv/301/info/dicominfo.tsv /Volumes/Project0255/code

2.2 Create the heuristic file

Create the following python file and save it in the code folder. There is one functional task (func_movie) and one anatomical (t1w). Dataset_3 and 4 have a field map as well (fmap_phase and fmap_magnitude)

Create a heuristic to automatically convert the files:

import os
def create_key(template, outtype=('nii.gz',), annotation_classes=None):
    if template is None or not template:
        raise ValueError('Template must be a valid format string')
    return template, outtype, annotation_classes
def infotodict(seqinfo):
    """Heuristic evaluator for determining which runs belong where
    allowed template fields - follow python string module:
    item: index within category
    subject: participant id
    seqitem: run number during scanning
    subindex: sub index within group
    session: session id (only for dataset_1)
    """
    
    t1w1 = create_key('sub-{subject}/{session}/anat/sub-{subject}_{session}_T1w')
    func_movie1 = create_key('sub-{subject}/{session}/func/sub-{subject}_{session}_task-movie_bold')

    t1w = create_key('sub-{subject}/anat/sub-{subject}_T1w')
    func_movie = create_key('sub-{subject}/func/sub-{subject}_task-movie_bold')
    func_movie_echo_1 = create_key('sub-{subject}/func/sub-{subject}_task-movie_echo-1_bold')
    func_movie_echo_2 = create_key('sub-{subject}/func/sub-{subject}_task-movie_echo-2_bold')
    fmap_phase = create_key('sub-{subject}/fmap/sub-{subject}_phasediff')
    fmap_magnitude = create_key('sub-{subject}/fmap/sub-{subject}_magnitude')
    
    info = {t1w1: [], func_movie1: [], t1w: [], func_movie: [], fmap_phase: [], fmap_magnitude: [],
            func_movie_echo_1: [], func_movie_echo_2: []} 
    
    for idx, s in enumerate(seqinfo):
        if ('T1W_1mm_sag SENSE' in s.protocol_name):
            info[t1w1].append(s.series_id)
        if ('ToM_PartlyCloudy SENSE' in s.protocol_name):
            info[func_movie1].append(s.series_id)
        if ('t1_mpr_ns_sag_iso_ADNI_32ch' in s.protocol_name):
            info[t1w].append(s.series_id)
        if ('t1_mpr_ns_sag_P2_ADNI_32ch' in s.protocol_name):
            info[t1w].append(s.series_id)
        if (s.dim4 == 175) and ('FMRI_MB2_p2_2MMISO_TR2_movie' in s.protocol_name):
            info[func_movie].append(s.series_id)
        if (s.dim4 == 175) and ('FMRI_MB2_movie_p2_2MMISO_TR2' in s.protocol_name):
            info[func_movie].append(s.series_id)
        if (s.dim4 == 170) and ('ep2d_ToM_Loc' in s.protocol_name):
            info[func_movie].append(s.series_id)
        if (s.dim4 == 175) and ('ep2d_ToM_Loc' in s.protocol_name):
            info[func_movie].append(s.series_id)
        if (s.dim4 == 175) and ('ep2d_ToM_Loc_boldTR2' in s.protocol_name):
            info[func_movie].append(s.series_id)
        if (s.TE == 13) and ('BP_ep2d_multiecho_32ch_p3_TOM' in s.protocol_name):
            info[func_movie_echo_1].append(s.series_id)
        if (s.TE == 31.36) and ('BP_ep2d_multiecho_32ch_p3_TOM' in s.protocol_name):
            info[func_movie_echo_2].append(s.series_id)
        if (s.dim3 == 92) and ('gre_field_mapping_AAH' in s.protocol_name):
            info[fmap_magnitude].append(s.series_id)
        if (s.dim3 == 46) and ('gre_field_mapping_AAH' in s.protocol_name):
            info[fmap_phase].append(s.series_id)
        if (s.dim3 == 64) and ('gre_field_mapping_AAH' in s.protocol_name):
            info[fmap_magnitude].append(s.series_id)
        if (s.dim3 == 32) and ('gre_field_mapping_AAH' in s.protocol_name):
            info[fmap_phase].append(s.series_id)
    return info

Use the heuristic file to convert the Dicom files to .nii.gz (nifti) and create .json files:

docker run --rm -it -v /Volumes/Project0255/:/base nipy/heudiconv:latest -d /base/dataset_4/sourcedata/sub-{subject}/*.IMA -o /base/dataset_4 -f /base/code/heuristic_anthrom.py -s 401 -c dcm2niix -b --overwrite

For dataset_1 (for dataset_1 add ses-{session}/ and –ss 01 and .dcm). Movie for sub-101 and 102 is in ses-02:

docker run --rm -it -v /Volumes/Project0255/:/base nipy/heudiconv:latest -d /base/dataset_1/sourcedata/sub-{subject}/ses-{session}/*.dcm -o /base/dataset_1 -f /base/code/heuristic_anthrom.py -s 121 -ss 02 -c dcm2niix -b --overwrite

On the grid do (Sub-116 was done manually in dcm2niigui):

Type in bash before running

Dataset_1:

singularity run -B /analyse/Project0255/:/base /analyse/Project0255/my_images/heudiconv_latest.sif -d /base/dataset_1/sourcedata/sub-{subject}/ses-{session}/*.dcm -o /base/dataset_1/ -f /base/code/heuristic_anthrom.py -s 116 -ss 01 -c dcm2niix -b --overwrite

Dataset_2 - 4:

singularity run -B /analyse/Project0255/:/base /analyse/Project0255/my_images/heudiconv_latest.sif -d /base/dataset_2/sourcedata/sub-{subject}/*.IMA -o /base/dataset_2/ -f /base/code/heuristic_anthrom.py -s 201 -c dcm2niix -b --overwrite

2.3 Anonymize the data

Deface using Pydeface:

#!/bin/bash

set -e 
####For loop that defaces the MRI per subject and replaces the old MRI with the new defaced MRI
rootfolder=/Volumes/Project0255/dataset_4

for subj in 401; do
    echo "Defacing participant $subj"
pydeface ${rootfolder}/sub-${subj}/anat/sub-${subj}_T1w.nii.gz
rm -f ${rootfolder}/sub-${subj}/anat/sub-${subj}_T1w.nii.gz
mv ${rootfolder}/sub-${subj}/anat/sub-${subj}_T1w_defaced.nii.gz ${rootfolder}/sub-${subj}/anat/sub-${subj}_T1w.nii.gz 
done

For dataset_1: ses-01: 101 102 103 107 112 113 117 118 119 122 123 124 128 ses-02: 104 105 106 108 109 110 111 115 116 120 121 125 126 127

#!/bin/bash

set -e 
rootfolder=/Volumes/Project0255/dataset_1

for subj in 129; do
    echo "Defacing participant $subj"
for session in 01; do
for echo in 1 2 3 4 5; do
pydeface ${rootfolder}/sub-${subj}/ses-${session}/anat/sub-${subj}_ses-${session}_echo-${echo}_T1w.nii.gz
rm -f ${rootfolder}/sub-${subj}/ses-${session}/anat/sub-${subj}_ses-${session}_echo-${echo}_T1w.nii.gz 
mv ${rootfolder}/sub-${subj}/ses-${session}/anat/sub-${subj}_ses-${session}_echo-${echo}_T1w_defaced.nii.gz ${rootfolder}/sub-${subj}/ses-${session}/anat/sub-${subj}_ses-${session}_echo-${echo}_T1w.nii.gz 
done
done
done

2.4 Update the .json file for the fmaps for dataset_3 and dataset_4

You need to specify “IntendedFor” field in the _phasediff.json files to point which scans the estimated fieldmap should be applied to.

Run the following script (thanks to Michele Svanera for the code):

python change_json.py

2.5 Combine the dual-echo runs for dataset_4

For dataset_4 we need to combine the two echo’s (see NeuroStar for more info. We created a dual_sum volume by adding the two images together (see Halai et al. 2014.

Run the following script (thanks to Tyler Morgan for the code):

python sum_echo.py

2.6 Theory-of-Mind event protocols

Create tsv file for functional localiser. Event coding (in s; 10s of fixation before movie starts; accounting for hemodynamic lag) is based on Richardson et al. 2018 - reverse correlation analyses.

Note: For sub-322 the trigger was at the start of the movie (thus create a different tsv, with event - 10s). Check the triggers for dataset_1.

PartlyCloudy <- data.frame(onset = c(86, 98, 120, 176, 238, 252, 300, 70, 92, 106, 136, 194, 210, 228, 262, 312), #create the events (same for every sub)
                           duration = c(4, 6, 4, 16, 6, 8, 6, 4, 2, 4, 10, 4, 12, 6, 6, 4),
                           trial_type = c(rep("mental",7), rep("pain",9)))

#dataset_1
for (sub in 102:129){ #note: localisers for sub-101 are in ses-02
  filename = paste("/Volumes/Project0255/dataset_1/sub-", sub, "/ses-01/func/sub-", sub, "_ses-01_task-movie_events.tsv", sep ="")
write.table(PartlyCloudy, file = filename, sep="\t", row.names = FALSE, quote = FALSE)
}
#dataset_2
for (sub in 201:235){ 
  filename = paste("/Volumes/Project0255/dataset_2/sub-", sub, "/func/sub-", sub, "_task-movie_events.tsv", sep ="")
write.table(PartlyCloudy, file = filename, sep="\t", row.names = FALSE, quote = FALSE)
}
#dataset_3
for (sub in 301:322){ #note: localisers for sub-322 should have t-10 (no trigger) <-manually correct this
  filename = paste("/Volumes/Project0255/dataset_3/sub-", sub, "/func/sub-", sub, "_task-movie_events.tsv", sep ="")
write.table(PartlyCloudy, file = filename, sep="\t", row.names = FALSE, quote = FALSE)
}
#dataset_4
for (sub in 401:422){ 
  filename = paste("/Volumes/Project0255/dataset_4/sub-", sub, "/func/sub-", sub, "_task-movie_events.tsv", sep ="")
write.table(PartlyCloudy, file = filename, sep="\t", row.names = FALSE, quote = FALSE)
}

2.6 BIDS validation

Use the BIDS-Validator to check if the dataset is BIDS compliant:

docker run -ti --rm -v /Volumes/Project0255/dataset_4:/data:ro bids/validator /data

3. Preprocessing

3.1 Run MRQIC

MRIQC is a docker tool to do quality control of the data. More info here.

MRIQC 0.14.2 was used:

docker run -it --rm -v /Volumes/Project0255/dataset_1/:/data:ro -v /Volumes/Project0255/dataset_1/derivatives/mriqc:/out poldracklab/mriqc:0.14.2 /data /out participant --participant-label 101 -m T1w bold --ica --fft-spikes-detector 

On the grid do (cd in /analyse folder):

singularity run --cleanenv /analyse/Project0255/my_images/mriqc-0.14.2.simg /analyse/Project0255/dataset_1 /analyse/Project0255/dataset_1/derivatives/mriqc participant --participant-label 123 -m T1w bold --ica --fft-spikes-detector -w /analyse/Project0255/work

Run it seperately for the datasets. Change participant to group to create the group reports:

docker run -it --rm -v /Volumes/Project0255/dataset_4/:/data:ro -v /Volumes/Project0255/dataset_4/derivatives/mriqc:/out poldracklab/mriqc:0.14.2 /data /out group

3.2 Compare MRIQC

Plot the output. This is based on MRIQCeption. The MRIQCeption Visualization by Catherine Walsh was adapted. Adjust the filter if you want to look at different measures.

Adjust this to your liking (e.g. bold: fd_mean, fd_perc, dvars_std, dvars_vstd, gcor, tsnr, t1w: cjv, cnr, snr, efc, inu, wm2max, fwhm) and modality (bold or t1w):

QCmeasure <- "fd_mean" 
modality <- "bold"

Run the following code. Change the script below to load the group results for the different datasets:

#libraries
library("tidyverse")
source("/Volumes/Project0255/code/R_rainclouds.R")

#load own data
DF.dataset1  <- read_tsv(file = paste("/Volumes/Project0255/dataset_1/derivatives/mriqc/group_", modality, ".tsv", sep ="")) %>%
  gather("measure", "value", 2:46) %>%
  select("bids_name","measure", "value")

DF.dataset2 <- read_tsv(file = paste("/Volumes/Project0255/dataset_2/derivatives/mriqc/group_", modality, ".tsv", sep ="")) %>%
  gather("measure", "value", 2:46) %>%
  select("bids_name","measure", "value")

DF.dataset3 <- read_tsv(file = paste("/Volumes/Project0255/dataset_3/derivatives/mriqc/group_", modality, ".tsv", sep ="")) %>%
  gather("measure", "value", 2:46) %>%
  select("bids_name","measure", "value")

DF.dataset4 <- read_tsv(file = paste("/Volumes/Project0255/dataset_4/derivatives/mriqc/group_", modality, ".tsv", sep ="")) %>%
  gather("measure", "value", 2:46) %>%
  select("bids_name","measure", "value") 

#select the most relevant measures
#selectionMeasure <- c("snr", "tsnr", "efc", "fber", "gsr_x", "gsr_y", "dvars_nstd", "dvars_std", "dvars_vstd", "gcor", "fd_mean", "fd_number", "fd_percentage", "spikes", "aor", "aqi")

#combine data
DF.full <- bind_rows(DF.dataset1, DF.dataset2, DF.dataset3,  DF.dataset4, .id = "dataset") %>%
  group_by(dataset) %>% 
  filter(measure == QCmeasure) #%in% c(selectionMeasure)) 

#create raincloud plot (check out the [github](https://github.com/RainCloudPlots/) or [preprint](https://wellcomeopenresearch.org/articles/4-63/v1)
p <- ggplot(DF.full,aes(x=dataset,y=value,fill=dataset))+
  geom_flat_violin(position=position_nudge(x = .2, y = 0),adjust =2, trim = FALSE, alpha = .5, colour = NA)+
  geom_point(aes(colour = dataset), position=position_jitter(width = .05), size = .5, shape = 20)+
  geom_boxplot(aes(x=dataset,y=value),position=position_nudge(x = .1, y = 0),outlier.shape = NA, alpha = .5, width = .1, colour = "black")+ 
  #facet_wrap(. ~ dataset) +
  theme_classic() + ylab(QCmeasure) + scale_fill_brewer(palette = "Reds") +
  scale_colour_brewer(palette = "Reds") + ggtitle(paste("Comparison of", modality, "QC measure", QCmeasure, "between datasets")) +
  facet_wrap(~measure)
p

3.3 fMRIprep

fMRIprep is a docker tool for preprocessing of the fMRI data. More info here

fMRIprep version 1.5.2 was used on a local iMac.

If you run into memory problems you can use –skip_bids_validation; skipped the –write-graph flag to save space, and –use-syn-sdc only for dataset_1 and datatset_2.

If run on the GRID, cd into the analyse folder and run:

singularity run --cleanenv /analyse/Project0255/my_images/fmriprep-1.5.2.simg /analyse/Project0255/dataset_1/ /analyse/Project0255/dataset_1/derivatives participant --participant-label sub-129 --fs-license-file /analyse/Project0255/my_images/license.txt --skip_bids_validation --use-syn-sd --fs-no-reconall -w /analyse/Project0255/work/compute00

Resize functional files for two participants (sub-117 and sub-125) from dataset_1 (sub-{sub}_ses-01_task-movie_space-MNI152NLin2009cAsym_desc-preproc_bold.nii) to allow for group comparison (run this in MATLAB):

voxsiz = [3 3 3.5]; % new voxel size {mm}
V = spm_select([1 Inf],'image');
V = spm_vol(V);
for i=1:numel(V)
   bb        = spm_get_bbox(V(i));
   VV(1:2)   = V(i);
   VV(1).mat = spm_matrix([bb(1,:) 0 0 0 voxsiz])*spm_matrix([-1 -1 -1]);
   VV(1).dim = ceil(VV(1).mat \ [bb(2,:) 1]' - 0.1)';
   VV(1).dim = VV(1).dim(1:3);
   spm_reslice(VV,struct('mean',false,'which',1,'interp',0)); % 1 for linear
end

4. Analyses

4.1 Example script for first-level analysis

Example MATLAB script (dataset 3):

%========================================================================
%     SPM first-level analysis for fmriprep data in BIDS format
%========================================================================
%     This script is written by Ruud Hortensius and Michaela Kent
%     (University of Glasgow). Based upon a script written by 
%     Shengdong Chen (ACRLAB) and Stephan Heunis (TU Eindhoven).
%
%     Added: loop for runs
%     Parameters as specified by Saxelab: https://saxelab.mit.edu/theory-mind-and-pain-matrix-localizer-movie-viewing-experiment
%
%     Last updated: January 2020
%========================================================================

clear all 

%% Inputdirs
BIDS = spm_BIDS('/Volumes/Project0255/dataset_3/'); % Parse BIDS directory (easier to query info from dataset)
BIDSpreproc=fullfile(BIDS.dir,'derivatives/fmriprep'); % get the preprocessed directory

%sublist = spm_BIDS(BIDS,'subjects') %number of subjects
sublist = transpose(BIDS.participants.participant_id) %get subject list including the 'sub'
subex = [] 
sublist(subex) = []; %update the subjects

taskid='movie'; %specify the task to be analysed

numScans=175;  %The number of volumes per run <---

TR = 2;     % Repetition time, in seconds <---
unit='secs'; % onset times in secs (seconds) or scans (TRs)

%% Outputdirs
outputdir=fullfile(BIDS.dir,'derivatives/bids_spm/first_level');  % root outputdir for sublist
spm_mkdir(outputdir,char(sublist), char(taskid)); % create output directory

%% Loop for sublist
spm('Defaults','fMRI'); %Initialise SPM fmri
spm_jobman('initcfg');  %Initialise SPM batch mode

for i=1:length(sublist)
    
    
    %% Output dirs where you save SPM.mat
    subdir=fullfile(outputdir,sublist{i},taskid);
    
    %% Basic parameters
    matlabbatch{1}.spm.stats.fmri_spec.dir = {subdir};
    matlabbatch{1}.spm.stats.fmri_spec.timing.units = unit; % specified above
    matlabbatch{1}.spm.stats.fmri_spec.timing.RT = TR; % specified above
    matlabbatch{1}.spm.stats.fmri_spec.timing.fmri_t = 68; %<--- look into this
    matlabbatch{1}.spm.stats.fmri_spec.timing.fmri_t0 = 34; %<--- look into this
    
    %% Load input files for task specilized
    sub_inputdir=fullfile(BIDSpreproc,sublist{i},'func');
    sub_inputdirA=fullfile(BIDSpreproc,sublist{i},'anat');
    
    %------------------------------------------------------------------
    func=[sub_inputdir,filesep,sublist{i},'_task-',taskid,'_space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz'];
    func_nii=[sub_inputdir,filesep,sublist{i}, '_task-',taskid,'_space-MNI152NLin2009cAsym_desc-preproc_bold.nii'];
    if ~exist(func_nii,'file'), gunzip(func)
    end
    run_scans = spm_select('Expand',func_nii);
    
    matlabbatch{1}.spm.stats.fmri_spec.sess(1).scans = cellstr(run_scans);
    
    % Load the condition files
    events = spm_load([BIDS.dir,filesep,sublist{i},'/func/', sublist{i},'_task-',taskid,'_events.tsv']) %load TSV condition file
    
    names{1} = 'mental';
    t = strcmp(names{1}, events.trial_type)
    onsets{1} = transpose(events.onset(t));
    durations{1} = transpose(events.duration(t));
    
    names{2} = 'pain';
    t = strcmp(names{2}, events.trial_type)
    onsets{2} = transpose(events.onset(t));
    durations{2} = transpose(events.duration(t));
    
    
    file_mat = [subdir,filesep,sublist{i},'_task-',taskid,'_conditions.mat'];
    save(file_mat, 'names', 'onsets', 'durations')
    matlabbatch{1}.spm.stats.fmri_spec.sess(1).cond = struct('name', {}, 'onset', {}, 'duration', {}, 'tmod', {}, 'pmod', {}, 'orth', {});
    matlabbatch{1}.spm.stats.fmri_spec.sess(1).multi = {file_mat};
    
    % Confounds file
    confounds=spm_load([sub_inputdir,filesep,sublist{i},'_task-',taskid,'_desc-confounds_regressors.tsv'])  ;
    confounds_matrix=[confounds.framewise_displacement, confounds.a_comp_cor_00,confounds.a_comp_cor_01,confounds.a_comp_cor_02,confounds.a_comp_cor_03, confounds.a_comp_cor_04,confounds.a_comp_cor_05, confounds.trans_x, confounds.trans_y, confounds.trans_z, confounds.rot_x, confounds.rot_y, confounds.rot_z];
    confounds_name=[subdir,filesep,sublist{i},'_task-',taskid,'_acomcorr.txt'];
    
    confounds_matrix(isnan(confounds_matrix)) = 0 % nanmean(confounds_matrix); %check this <-----
    
    if ~exist(confounds_name,'file'), dlmwrite(confounds_name,confounds_matrix)
    end
    matlabbatch{1}.spm.stats.fmri_spec.sess(1).multi_reg = {confounds_name};
    matlabbatch{1}.spm.stats.fmri_spec.sess(1).hpf = 128; % High-pass filter (hpf) without using consine
    
    %% Model  (Default)
    matlabbatch{1}.spm.stats.fmri_spec.fact = struct('name', {}, 'levels', {});
    matlabbatch{1}.spm.stats.fmri_spec.bases.hrf.derivs = [0 0];
    matlabbatch{1}.spm.stats.fmri_spec.volt = 1;
    matlabbatch{1}.spm.stats.fmri_spec.global = 'Scaling';
    mask=[sub_inputdirA,filesep,sublist{i},'_space-MNI152NLin2009cAsym_label-GM_probseg.nii.gz'];
    mask_nii=[sub_inputdirA,filesep,sublist{i},'_space-MNI152NLin2009cAsym_label-GM_probseg.nii'];
    
    if ~exist(mask_nii,'file'), gunzip(mask)
    end
    mask_nii=[mask_nii, ',1']
    matlabbatch{1}.spm.stats.fmri_spec.mask = {mask_nii};
    matlabbatch{1}.spm.stats.fmri_spec.mthresh = 0.8;
    matlabbatch{1}.spm.stats.fmri_spec.cvi = 'none';
    
    %% Model estimation (Default)subdir
    matlabbatch{2}.spm.stats.fmri_est.spmmat = {[subdir filesep 'SPM.mat']};
    matlabbatch{2}.spm.stats.fmri_est.write_residuals = 0;
    matlabbatch{2}.spm.stats.fmri_est.method.Classical = 1;
    
    %% Contrasts
    matlabbatch{3}.spm.stats.con.spmmat = {[subdir filesep 'SPM.mat']};
    % Set contrasts of interest.
    matlabbatch{3}.spm.stats.con.consess{1}.tcon.name = 'mental_pain';
    matlabbatch{3}.spm.stats.con.consess{1}.tcon.convec = [1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0];
    matlabbatch{3}.spm.stats.con.consess{2}.tcon.name = 'pain_mental';
    matlabbatch{3}.spm.stats.con.consess{2}.tcon.convec = [-1 1 0 0 0 0 0 0 0 0 0 0 0 0 0];
    matlabbatch{3}.spm.stats.con.delete = 0;
    
    %% Run matlabbatch jobs
    spm_jobman('run',matlabbatch);
    
end

4.2 First-level analysis

Run the followin commands in the terminal.

Dataset_1:

cd "/Volumes/Project0255/code/"
matlab -batch "BIDS_SPM_firstlevel_tom_dataset1"
matlab -batch "BIDS_SPM_firstlevel_tom_dataset1_ppn101"
matlab -batch "BIDS_SPM_firstlevel_tom_dataset1_ppn114"

Dataset_2:

cd "/Volumes/Project0255/code/"
matlab -batch "BIDS_SPM_firstlevel_tom_dataset2_ppn201_202"

Dataset_3:

cd "/Volumes/Project0255/code/"
matlab -batch "BIDS_SPM_firstlevel_tom_dataset3"

Dataset_4:

cd "/Volumes/Project0255/code/"
matlab -batch "BIDS_SPM_firstlevel_tom_dataset4"

4.3 Create group mask

Create a group average for the GM_probseg.nii for each dataset in Matlab (change the code per dataset; run this in MATLAB):

clear all

spm('Defaults','fMRI');
spm_jobman('initcfg');  

BIDS = spm_BIDS('/Volumes/Project0255/dataset_3'); %change this
BIDSfirst=fullfile(BIDS.dir,'derivatives/fmriprep'); 

sublist = transpose(BIDS.participants.participant_id) 
subex = [] %subjects that don't have an anatomical (14 dataset_1)
sublist(subex) = []; 

for i=1:length(sublist)
    subdir=fullfile(BIDSfirst,sublist{i}, 'anat')
    matlabbatch{1}.spm.util.imcalc.input{i,1} = [subdir, filesep, sublist{i}, '_space-MNI152NLin2009cAsym_label-GM_probseg.nii,1']
end
matlabbatch{1}.spm.util.imcalc.output = 'dataset3_averageGM';
matlabbatch{1}.spm.util.imcalc.outdir = {'/Volumes/Project0255/dataset_3/derivatives/fmriprep'}; %change this
matlabbatch{1}.spm.util.imcalc.expression = 'mean(X)';
matlabbatch{1}.spm.util.imcalc.var = struct('name', {}, 'value', {});
matlabbatch{1}.spm.util.imcalc.options.dmtx = 1;
matlabbatch{1}.spm.util.imcalc.options.mask = 0;
matlabbatch{1}.spm.util.imcalc.options.interp = 1;
matlabbatch{1}.spm.util.imcalc.options.dtype = 4;

spm_jobman('run',matlabbatch);

4.4 Example script for second-level whole-brain analysis

Example MATLAB script (dataset 3):

%========================================================================
%     SPM second-level analysis for fmriprep data in BIDS format
%========================================================================
%     This script is written by Ruud Hortensius and Michaela Kent 
%     (University of Glasgow) 
%
%     Last updated: January 2020
%========================================================================


clear all

%% Inputdirs
BIDS = spm_BIDS('/Volumes/Project0255/dataset_3'); % Parse BIDS directory (easier to query info from dataset)
BIDSfirst=fullfile(BIDS.dir,'derivatives/bids_spm/first_level'); % get the first-level directory

sublist = transpose(BIDS.participants.participant_id) %get subject list including the 'sub'
subex = [] %subjects that don't have a second-session
sublist(subex) = []; %update the subjects

%nsession = spm_BIDS(BIDS,'sessions') %how many sessions? careful, sometimes collapsing across sessions not wanted
%sessionid = 'ses-01' %get session id

taskid='movieHC'; %specify the task to be analysed

contrast='con_0001'; %specify the contrast to be analysed
contrast_name='mental_hc'; %specify the name of the contrast

smoothing = 1; %soomthing of first-level contrasts (1=yes, 0=no)
s_kernel = [5 5 5]

%% Outputdirs
outputdir=fullfile(BIDS.dir,'derivatives/bids_spm/second_level', char(contrast_name));  % root outputdir for sublist
spm_mkdir(outputdir); % create output directory 

spm('Defaults','fMRI'); %Initialise SPM fmri
spm_jobman('initcfg');  %Initialise SPM batch mode


%% Smoothing of first-level contrasts
if smoothing == 1
    for i=1:length(sublist)
        subdir=fullfile(BIDSfirst,sublist{i}, taskid);
        matlabbatch{1}.spm.spatial.smooth.data{i,1} = [subdir, filesep, contrast, '.nii,1'];
        matlabbatch{1}.spm.spatial.smooth.fwhm = s_kernel;
        matlabbatch{1}.spm.spatial.smooth.dtype = 0;
        matlabbatch{1}.spm.spatial.smooth.im = 0;
        matlabbatch{1}.spm.spatial.smooth.prefix = 's';
    end
    spm_jobman('run',matlabbatch);
    
    clear matlabbatch
end


%% Load the contrasts
matlabbatch{1}.spm.stats.factorial_design.dir = {outputdir};

for i=1:length(sublist)
    subdir=fullfile(BIDSfirst,sublist{i}, taskid);
    if smoothing == 1
        matlabbatch{1,1}.spm.stats.factorial_design.des.t1.scans{i,1} = [subdir, filesep, 's', contrast, '.nii,1']
    else
        matlabbatch{1,1}.spm.stats.factorial_design.des.t1.scans{i,1} = [subdir, filesep, contrast, '.nii,1']
    end
end

matlabbatch{1}.spm.stats.factorial_design.cov = struct('c', {}, 'cname', {}, 'iCFI', {}, 'iCC', {});
matlabbatch{1}.spm.stats.factorial_design.multi_cov = struct('files', {}, 'iCFI', {}, 'iCC', {});
matlabbatch{1}.spm.stats.factorial_design.masking.tm.tm_none = 1;
matlabbatch{1}.spm.stats.factorial_design.masking.im = 1;
matlabbatch{1}.spm.stats.factorial_design.masking.em = {''};
matlabbatch{1}.spm.stats.factorial_design.globalc.g_omit = 1;
matlabbatch{1}.spm.stats.factorial_design.globalm.gmsca.gmsca_no = 1;
matlabbatch{1}.spm.stats.factorial_design.globalm.glonorm = 1;

%% Model estimation 
matlabbatch{2}.spm.stats.fmri_est.spmmat = {[outputdir filesep 'SPM.mat']};
matlabbatch{2}.spm.stats.fmri_est.write_residuals = 0;
matlabbatch{2}.spm.stats.fmri_est.method.Classical = 1;

%% Contrast
%--------------------------------------------------------------------------
matlabbatch{3}.spm.stats.con.spmmat = {[outputdir filesep 'SPM.mat']};
matlabbatch{3}.spm.stats.con.consess{1}.tcon.name = contrast_name;
matlabbatch{3}.spm.stats.con.consess{1}.tcon.weights = 1;
matlabbatch{3}.spm.stats.con.consess{1}.tcon.sessrep = 'none';
matlabbatch{3}.spm.stats.con.delete = 0;

%% Results
%--------------------------------------------------------------------------
matlabbatch{4}.spm.stats.results.spmmat = {[outputdir filesep 'SPM.mat']};
matlabbatch{4}.spm.stats.results.conspec.titlestr = '';
matlabbatch{4}.spm.stats.results.conspec.contrasts = 1;
matlabbatch{4}.spm.stats.results.conspec.threshdesc = 'none';
matlabbatch{4}.spm.stats.results.conspec.thresh = 0.001;
matlabbatch{4}.spm.stats.results.conspec.extent = 5;
matlabbatch{4}.spm.stats.results.conspec.conjunction = 1;
matlabbatch{4}.spm.stats.results.conspec.mask.image.name = {'/Volumes/Project0255/dataset_3/derivatives/fmriprep/dataset3_averageGM.nii,1'};
matlabbatch{4}.spm.stats.results.conspec.mask.image.mtype = 0;
matlabbatch{4}.spm.stats.results.units = 1;
matlabbatch{4}.spm.stats.results.export{1}.pdf = true;
matlabbatch{4}.spm.stats.results.export{2}.jpg = true;
matlabbatch{4}.spm.stats.results.export{3}.csv = true;
matlabbatch{4}.spm.stats.results.export{4}.tspm.basename = contrast_name;

%% Run matlabbatch jobs
spm_jobman('run',matlabbatch);

4.5 Second-level whole-brain analysis

Run it seperately for the datasets:

cd "/Volumes/Project0255/code/"
matlab -batch "BIDS_SPM_secondlevel_tom_dataset1"
matlab -batch "BIDS_SPM_secondlevel_tom_dataset2"
matlab -batch "BIDS_SPM_secondlevel_tom_dataset3"
matlab -batch "BIDS_SPM_secondlevel_tom_dataset4"

4.6 ToM fROI analysis

Run the following (ROI_extract.m) script in matlab (change the code per dataset and roi and contrast - run this in MATLAB):

%========================================================================
%     fROI analysis for fmriprep data in BIDS format
%========================================================================
%     This script is written by  Michaela Kent and Ruud Hortensius
%     (University of Glasgow) 
%
%     Last updated: January 2020
%========================================================================
clear all
%add marsbar to path
marsbar('on')

%% Inputdirs
BIDS = spm_BIDS('/Volumes/Project0255/dataset_4'); % parse BIDS directory (easier to query info from dataset)
BIDSsecond=fullfile(BIDS.dir,'derivatives/bids_spm/second_level'); % get the second-level directory

contrastid = 'mental' %can be either mental (vs. pain) or pain (vs. mental)
networkid = 'tom' %can be either tom (theory-of-mind) or pain (pain matrix)

%% Outputdirs
outputdir=fullfile(BIDS.dir,'derivatives/roi', networkid);  % root outputdir for sublist
spm_mkdir(outputdir); % create output directory 

%% Load design matrix
spm_name = spm_load(fullfile(BIDSsecond, filesep, contrastid , 'SPM.mat'))
D  = mardo(spm_name);


%% Load rois
parcels = dir(fullfile(BIDS.dir,'derivatives/parcels/', networkid))
parcels = struct2cell(parcels(arrayfun(@(x) ~strcmp(x.name(1),'.'),parcels)))
parcels(2:6,:) = []

for i=1:length(parcels) 
    roi = fullfile(BIDS.dir,'derivatives/parcels/',  networkid, parcels{i})
    R  = maroi(roi);
    % Fetch data into marsbar data object
    mY  = get_marsy(R, D, 'mean');
    roi_data = summary_data(mY); % get summary time course(s)
    roi_name = [outputdir,filesep,parcels{i},'.tsv'];
    dlmwrite(roi_name,roi_data);
end

4.7 Custom steps

Add sub-201 and sub-202 to get the fROI data (different parameters, not included in the whole-brain analysis):

cd "/Volumes/Project0255/code/"
matlab -batch "BIDS_SPM_secondlevel_tom_dataset2_201_202"
matlab -batch "ROI_extract_201_202"

5. IDAQ

5.1 Calculation of individual scores:

Dataset 2: sub-206-212, 219, 221-22, 224-25, 228, 231, 233-34 completed a version with the scale ranging from 1-10 instead of 0-10. Analyses should be run with and without these participants:

sub_ex = c(206:212, 219, 221:222, 224:225, 228, 231, 233:234)

Get the IDAQ data for all the participants:

library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ───────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.0 ──
✓ ggplot2 3.3.1     ✓ purrr   0.3.4
✓ tibble  3.0.1     ✓ dplyr   1.0.0
✓ tidyr   1.1.0     ✓ stringr 1.4.0
✓ readr   1.3.1     ✓ forcats 0.5.0
── Conflicts ──────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
#load data (/Volumes/Project0255/dataset_1/sourcedata/)
DF.d1  <- read_csv(file = paste("IDAQ_dataset1.csv", sep ="")) %>%
  gather("sub", "value", 4:32)
Parsed with column specification:
cols(
  .default = col_double(),
  scale = col_character(),
  subscale = col_character()
)
See spec(...) for full column specifications.
DF.d2  <- read_csv(file = paste("IDAQ_dataset2.csv", sep ="")) %>%
  gather("sub", "value", 4:38) 
Parsed with column specification:
cols(
  .default = col_double(),
  scale = col_character(),
  subscale = col_character()
)
See spec(...) for full column specifications.
DF.d3  <- read_csv(file = paste("IDAQ_dataset3.csv", sep ="")) %>%
  gather("sub", "value", 4:25) 
Parsed with column specification:
cols(
  .default = col_double(),
  scale = col_character(),
  subscale = col_character()
)
See spec(...) for full column specifications.
DF.d4  <- read_csv(file = paste("IDAQ_dataset4.csv", sep ="")) %>%
  gather("sub", "value", 4:25) 
Parsed with column specification:
cols(
  .default = col_double(),
  scale = col_character(),
  subscale = col_character()
)
See spec(...) for full column specifications.
DF.idaq <- bind_rows(DF.d1, DF.d2, DF.d3, DF.d4, .id = "dataset") %>%
  mutate(sub=gsub('sub-','',sub))%>%
  transform(sub=as.integer(sub)) %>%
  mutate(scale = as.factor(ifelse(scale == "IDAQ-NA", "IDAQNA", "IDAQ")))

rm(DF.d1, DF.d2, DF.d3, DF.d4)

5.2 Reliability of IDAQ

Check the reliability of the IDAQ scale:

library("psych")

Attaching package: ‘psych’

The following objects are masked from ‘package:ggplot2’:

    %+%, alpha
DF.idaq %>% 
  filter(scale == "IDAQ") %>%
  #filter(!sub %in% sub_ex) %>% 
  select(-scale, -subscale)  %>%
  spread(itemnr, value) %>%
  select(-sub, -dataset) %>%
  alpha(na.rm = TRUE)

Reliability analysis   
Call: alpha(x = ., na.rm = TRUE)

 

 lower alpha upper     95% confidence boundaries
0.75 0.8 0.86 

 Reliability if an item is dropped:

 Item statistics 

5.3 Reliability of IDAQ-NA

Check the reliability of the IDAQ-NA scale:

DF.idaq %>% 
  filter(scale == "IDAQNA") %>%
  filter(!sub %in%  sub_ex) %>% 
  select(-scale, -subscale)  %>%
  spread(itemnr, value) %>%
  select(-sub, -dataset) %>%
  alpha(na.rm = TRUE)

Reliability analysis   
Call: alpha(x = ., na.rm = TRUE)

 

 lower alpha upper     95% confidence boundaries
0.51 0.62 0.73 

 Reliability if an item is dropped:

 Item statistics 

5.4 Differences between datasets

Test if there are differences in IDAQ and IDAQ-NA scores between datasets.

Before fitting any model we establish which link function we need to use. This code is taken from Kevin Stadler’s github. In short, it uses the ordinal package to (quickly) find the link function that fits the data:

library(ordinal)

Attaching package: ‘ordinal’

The following object is masked from ‘package:dplyr’:

    slice
cumulativemodelfit <- function(formula, data, links=c("logit", "probit", "cloglog", "cauchit"),
    thresholds=c("flexible", "equidistant"), verbose=TRUE) {
  names(links) <- links
  names(thresholds) <- thresholds
  llks <- outer(links, thresholds,
    Vectorize(function(link, threshold)
      # catch error for responses with 2 levels
      tryCatch(ordinal::clm(formula, data=data, link=link, threshold=threshold)$logLik,
        error = function(e) NA)))
  print(llks)
  if (verbose) {
    bestfit <- which.max(llks)
    cat("\nThe best link function is ", links[bestfit %% length(links)], " with a ",
    thresholds[1 + bestfit %/% length(thresholds)], " threshold (logLik ", llks[bestfit],
    ")\n", sep="")
  }
  invisible(llks)
}

Run the analyse for the anthropomorphism subscale:

DF.test = DF.idaq %>% 
  filter(scale == "IDAQ") %>% 
  mutate_all(as.factor) %>%
  mutate(value = factor(value, levels=c(0:10), ordered=TRUE)) #add contrast coding?

Get the link function:

cumulativemodelfit(value ~ 1, data=DF.test)
         flexible equidistant
logit   -3559.563   -3638.793
probit  -3559.563   -3629.921
cloglog -3559.563   -3663.966
cauchit -3559.563   -3629.921

The best link function is logit with a flexible threshold (logLik -3559.563)
  1. First cumulative ordinal model with dataset as fixed factor:
library(brms)
Registered S3 methods overwritten by 'htmltools':
  method               from         
  print.html           tools:rstudio
  print.shiny.tag      tools:rstudio
  print.shiny.tag.list tools:rstudio
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio
Loading 'brms' package (version 2.13.0). Useful instructions
can be found by typing help('brms'). A more detailed introduction
to the package is available through vignette('brms_overview').

Attaching package: ‘brms’

The following objects are masked from ‘package:ordinal’:

    ranef, VarCorr

The following object is masked from ‘package:psych’:

    cs

The following object is masked from ‘package:stats’:

    ar

Get summary and marginal effects:

  1. Second cumulative ordinal model with dataset as fixed factor and random intercepts for participant and itemnr:
ord.2 <- brm(
  value ~ 1 + dataset +
    (1|sub) + (1|itemnr),   
  data  = DF.test,  
  family  = cumulative("logit"),
  file = 'ord.2~random.RDS'
) 

Get summary and marginal effects:

  1. Category-specific model:
ord.3 <- brm(
  value ~ 1 + cs(dataset) +
    (cs(1)|sub) + (cs(1)|itemnr),
  data  = DF.test,  
  family = acat("logit"),
  file = 'ord.3~category.RDS'
)  

Get summary and marginal effects:

summary(ord.3) #prob = .99  for 99 credible intervals
 Family: acat 
  Links: mu = logit; disc = identity 
Formula: value ~ 1 + cs(dataset) + (cs(1) | sub) + (cs(1) | itemnr) 
   Data: DF.test (Number of observations: 1616) 
Samples: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup samples = 4000

Group-Level Effects: 
~itemnr (Number of levels: 15) 
                                Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(Intercept[1])                    1.53      0.40     0.91     2.50 1.00     1155     1765
sd(Intercept[2])                    1.45      0.37     0.89     2.35 1.00     1681     2421
sd(Intercept[3])                    0.67      0.22     0.31     1.17 1.00     1861     2731
sd(Intercept[4])                    0.38      0.24     0.03     0.90 1.00     1272     1754
sd(Intercept[5])                    0.78      0.26     0.33     1.35 1.00     1893     1828
sd(Intercept[6])                    0.74      0.26     0.31     1.34 1.00     1904     1671
sd(Intercept[7])                    0.28      0.21     0.01     0.79 1.00     1550     1807
sd(Intercept[8])                    0.96      0.32     0.49     1.76 1.00     1993     2602
sd(Intercept[9])                    0.46      0.32     0.03     1.23 1.00     1319     1923
sd(Intercept[10])                   0.61      0.48     0.03     1.87 1.00     1258     1742
cor(Intercept[1],Intercept[2])      0.51      0.20     0.07     0.84 1.00      866     1357
cor(Intercept[1],Intercept[3])      0.45      0.22    -0.03     0.82 1.00     2384     2663
cor(Intercept[2],Intercept[3])      0.36      0.23    -0.14     0.76 1.00     2784     2851
cor(Intercept[1],Intercept[4])      0.22      0.28    -0.36     0.71 1.00     3197     3066
cor(Intercept[2],Intercept[4])      0.15      0.29    -0.45     0.65 1.00     3717     2899
cor(Intercept[3],Intercept[4])      0.05      0.28    -0.50     0.59 1.00     3312     2588
cor(Intercept[1],Intercept[5])      0.28      0.24    -0.23     0.70 1.00     2434     3075
cor(Intercept[2],Intercept[5])      0.27      0.24    -0.23     0.69 1.00     2491     2833
cor(Intercept[3],Intercept[5])      0.22      0.25    -0.30     0.68 1.00     2156     2791
cor(Intercept[4],Intercept[5])     -0.04      0.29    -0.58     0.53 1.00     2030     3063
cor(Intercept[1],Intercept[6])      0.14      0.25    -0.36     0.60 1.00     2136     2688
cor(Intercept[2],Intercept[6])      0.19      0.25    -0.32     0.65 1.00     2660     2475
cor(Intercept[3],Intercept[6])      0.22      0.26    -0.29     0.68 1.00     2086     2497
cor(Intercept[4],Intercept[6])      0.09      0.29    -0.46     0.63 1.00     2129     2726
cor(Intercept[5],Intercept[6])      0.06      0.27    -0.45     0.57 1.00     2920     3194
cor(Intercept[1],Intercept[7])     -0.03      0.29    -0.58     0.53 1.00     3606     2999
cor(Intercept[2],Intercept[7])     -0.00      0.29    -0.56     0.55 1.00     3884     3058
cor(Intercept[3],Intercept[7])      0.06      0.29    -0.52     0.60 1.00     3212     3101
cor(Intercept[4],Intercept[7])      0.03      0.30    -0.54     0.60 1.00     3279     2615
cor(Intercept[5],Intercept[7])     -0.01      0.29    -0.57     0.54 1.00     3679     3098
cor(Intercept[6],Intercept[7])     -0.01      0.30    -0.57     0.58 1.00     3542     3406
cor(Intercept[1],Intercept[8])      0.33      0.23    -0.15     0.73 1.00     1872     2551
cor(Intercept[2],Intercept[8])      0.33      0.23    -0.17     0.73 1.00     2696     3075
cor(Intercept[3],Intercept[8])      0.38      0.23    -0.11     0.77 1.00     2340     2787
cor(Intercept[4],Intercept[8])      0.11      0.28    -0.44     0.62 1.00     2159     3123
cor(Intercept[5],Intercept[8])      0.39      0.23    -0.11     0.78 1.00     2418     3117
cor(Intercept[6],Intercept[8])      0.19      0.25    -0.34     0.64 1.00     2855     3150
cor(Intercept[7],Intercept[8])      0.03      0.29    -0.52     0.57 1.00     2854     3301
cor(Intercept[1],Intercept[9])      0.05      0.28    -0.49     0.59 1.00     3374     2894
cor(Intercept[2],Intercept[9])     -0.02      0.29    -0.56     0.52 1.00     3732     2813
cor(Intercept[3],Intercept[9])     -0.02      0.28    -0.55     0.53 1.00     3578     3082
cor(Intercept[4],Intercept[9])      0.10      0.30    -0.50     0.64 1.00     2700     2800
cor(Intercept[5],Intercept[9])     -0.03      0.29    -0.58     0.53 1.00     3211     2798
cor(Intercept[6],Intercept[9])      0.11      0.28    -0.46     0.61 1.00     3265     3624
cor(Intercept[7],Intercept[9])      0.03      0.30    -0.55     0.60 1.00     2714     3240
cor(Intercept[8],Intercept[9])     -0.06      0.29    -0.59     0.51 1.00     3220     3350
cor(Intercept[1],Intercept[10])     0.12      0.27    -0.44     0.63 1.00     3782     2939
cor(Intercept[2],Intercept[10])     0.14      0.28    -0.43     0.65 1.00     4177     3371
cor(Intercept[3],Intercept[10])     0.09      0.28    -0.46     0.61 1.00     3063     2990
cor(Intercept[4],Intercept[10])     0.08      0.28    -0.49     0.60 1.00     2526     3064
cor(Intercept[5],Intercept[10])     0.08      0.28    -0.48     0.60 1.00     3649     3117
cor(Intercept[6],Intercept[10])     0.12      0.28    -0.44     0.62 1.00     3097     3274
cor(Intercept[7],Intercept[10])     0.05      0.30    -0.54     0.61 1.00     2947     3559
cor(Intercept[8],Intercept[10])     0.09      0.28    -0.47     0.61 1.00     3249     3335
cor(Intercept[9],Intercept[10])     0.05      0.29    -0.53     0.60 1.00     2579     3241

~sub (Number of levels: 108) 
                                Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(Intercept[1])                    2.88      0.34     2.28     3.60 1.01     1201     2068
sd(Intercept[2])                    1.09      0.20     0.73     1.49 1.00     1303     2389
sd(Intercept[3])                    0.68      0.22     0.23     1.12 1.01      868      776
sd(Intercept[4])                    0.94      0.24     0.47     1.42 1.00     1061     1261
sd(Intercept[5])                    1.30      0.26     0.81     1.85 1.00     1058     1635
sd(Intercept[6])                    1.38      0.24     0.95     1.87 1.01     1305     2015
sd(Intercept[7])                    0.32      0.21     0.01     0.79 1.01      712     1274
sd(Intercept[8])                    0.85      0.22     0.42     1.30 1.00      968     1687
sd(Intercept[9])                    0.57      0.32     0.05     1.24 1.00      862      879
sd(Intercept[10])                   1.85      0.35     1.22     2.59 1.00     1843     2640
cor(Intercept[1],Intercept[2])     -0.14      0.18    -0.47     0.23 1.00     1401     1930
cor(Intercept[1],Intercept[3])     -0.19      0.20    -0.55     0.24 1.00     2775     2553
cor(Intercept[2],Intercept[3])      0.28      0.23    -0.19     0.71 1.00     1415     2032
cor(Intercept[1],Intercept[4])      0.16      0.20    -0.24     0.55 1.00     1595     2223
cor(Intercept[2],Intercept[4])      0.30      0.21    -0.11     0.70 1.00     1440     2021
cor(Intercept[3],Intercept[4])     -0.05      0.26    -0.52     0.49 1.00     1248     1752
cor(Intercept[1],Intercept[5])     -0.16      0.16    -0.47     0.17 1.00     1374     2214
cor(Intercept[2],Intercept[5])      0.25      0.20    -0.16     0.62 1.00      829     1729
cor(Intercept[3],Intercept[5])      0.20      0.23    -0.29     0.63 1.00      702     1516
cor(Intercept[4],Intercept[5])     -0.08      0.23    -0.50     0.41 1.01      791     1382
cor(Intercept[1],Intercept[6])     -0.11      0.15    -0.40     0.20 1.00     1745     2303
cor(Intercept[2],Intercept[6])     -0.05      0.20    -0.43     0.34 1.01      819     1698
cor(Intercept[3],Intercept[6])      0.02      0.23    -0.43     0.46 1.01      571     1353
cor(Intercept[4],Intercept[6])     -0.23      0.21    -0.61     0.21 1.01      606     1248
cor(Intercept[5],Intercept[6])     -0.59      0.15    -0.82    -0.27 1.00     1040     2118
cor(Intercept[1],Intercept[7])     -0.20      0.28    -0.68     0.40 1.00     3215     2971
cor(Intercept[2],Intercept[7])      0.02      0.28    -0.54     0.56 1.00     3606     3022
cor(Intercept[3],Intercept[7])      0.14      0.29    -0.45     0.67 1.00     2671     2602
cor(Intercept[4],Intercept[7])     -0.06      0.29    -0.59     0.52 1.00     3334     2996
cor(Intercept[5],Intercept[7])      0.06      0.28    -0.50     0.59 1.00     3439     2921
cor(Intercept[6],Intercept[7])      0.02      0.29    -0.54     0.57 1.00     3511     2715
cor(Intercept[1],Intercept[8])     -0.07      0.18    -0.41     0.28 1.00     2488     2570
cor(Intercept[2],Intercept[8])      0.31      0.20    -0.10     0.67 1.00     1162     2060
cor(Intercept[3],Intercept[8])      0.35      0.23    -0.16     0.72 1.00      819     1463
cor(Intercept[4],Intercept[8])     -0.04      0.23    -0.48     0.41 1.00     1159     2733
cor(Intercept[5],Intercept[8])      0.09      0.22    -0.35     0.51 1.00     1857     2560
cor(Intercept[6],Intercept[8])      0.29      0.21    -0.15     0.68 1.00     2214     3047
cor(Intercept[7],Intercept[8])      0.07      0.29    -0.49     0.59 1.01     1288     2341
cor(Intercept[1],Intercept[9])      0.10      0.25    -0.41     0.55 1.00     3369     2738
cor(Intercept[2],Intercept[9])      0.02      0.26    -0.48     0.54 1.00     2645     2805
cor(Intercept[3],Intercept[9])      0.16      0.29    -0.41     0.67 1.00     1209     2411
cor(Intercept[4],Intercept[9])     -0.01      0.28    -0.54     0.53 1.00     2334     2852
cor(Intercept[5],Intercept[9])      0.17      0.28    -0.41     0.66 1.00     2245     2352
cor(Intercept[6],Intercept[9])     -0.10      0.27    -0.60     0.45 1.00     2950     2782
cor(Intercept[7],Intercept[9])      0.04      0.30    -0.54     0.60 1.00     1735     2802
cor(Intercept[8],Intercept[9])      0.17      0.28    -0.40     0.67 1.00     2414     2281
cor(Intercept[1],Intercept[10])    -0.43      0.14    -0.69    -0.15 1.00     1790     2431
cor(Intercept[2],Intercept[10])    -0.20      0.19    -0.56     0.19 1.00      893     1953
cor(Intercept[3],Intercept[10])     0.15      0.23    -0.32     0.57 1.00      744     1878
cor(Intercept[4],Intercept[10])    -0.22      0.22    -0.64     0.22 1.01      889     1340
cor(Intercept[5],Intercept[10])     0.40      0.18     0.00     0.72 1.00     1373     2426
cor(Intercept[6],Intercept[10])    -0.32      0.18    -0.64     0.04 1.00     1843     2542
cor(Intercept[7],Intercept[10])     0.09      0.28    -0.48     0.60 1.00     1327     2446
cor(Intercept[8],Intercept[10])    -0.16      0.22    -0.57     0.28 1.00     1693     2621
cor(Intercept[9],Intercept[10])     0.02      0.27    -0.50     0.53 1.00     1748     2945

Population-Level Effects: 
              Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept[1]      0.65      0.78    -0.89     2.20 1.01      562     1036
Intercept[2]     -0.33      0.54    -1.43     0.72 1.00     1062     1907
Intercept[3]      0.25      0.40    -0.56     1.03 1.00      972     1874
Intercept[4]      0.50      0.43    -0.30     1.38 1.00     1218     1932
Intercept[5]     -0.47      0.50    -1.47     0.49 1.00     1185     1961
Intercept[6]      0.01      0.48    -0.93     0.96 1.00     1255     2374
Intercept[7]      0.00      0.31    -0.60     0.61 1.00     1692     2559
Intercept[8]      0.93      0.50    -0.01     1.96 1.00     1239     2046
Intercept[9]      0.91      0.47     0.03     1.87 1.00     1114     1800
Intercept[10]    -0.06      0.73    -1.38     1.56 1.00     1226     1671
dataset2[1]       4.14      0.88     2.56     5.94 1.00      644     1534
dataset2[2]      -0.46      0.43    -1.32     0.38 1.00     1263     1716
dataset2[3]       0.18      0.41    -0.63     0.98 1.00     1546     2427
dataset2[4]      -0.44      0.49    -1.41     0.56 1.00     1493     2234
dataset2[5]      -0.51      0.57    -1.64     0.58 1.00     1225     2184
dataset2[6]       0.19      0.56    -0.87     1.31 1.00     1336     1837
dataset2[7]       0.22      0.38    -0.51     0.99 1.00     1999     3036
dataset2[8]       0.20      0.45    -0.67     1.10 1.00     1565     2051
dataset2[9]      -0.03      0.49    -0.98     0.92 1.00     1320     2455
dataset2[10]     -0.34      0.74    -1.75     1.13 1.00     1177     1779
dataset3[1]       0.08      0.93    -1.76     1.96 1.00      636     1223
dataset3[2]       0.21      0.51    -0.81     1.23 1.00     1488     2479
dataset3[3]       0.21      0.43    -0.64     1.07 1.00     1389     2311
dataset3[4]      -0.49      0.55    -1.60     0.57 1.00     1218     1927
dataset3[5]      -0.87      0.64    -2.13     0.38 1.00     1344     2390
dataset3[6]       0.08      0.64    -1.15     1.37 1.00     1562     1953
dataset3[7]       0.25      0.45    -0.64     1.14 1.00     2077     2878
dataset3[8]      -0.22      0.51    -1.26     0.76 1.00     1950     2266
dataset3[9]      -0.09      0.57    -1.24     0.98 1.00     1605     2546
dataset3[10]     -1.26      0.91    -3.05     0.56 1.00     1571     2289
dataset4[1]      -0.12      0.89    -1.88     1.59 1.01      605      838
dataset4[2]       0.47      0.51    -0.52     1.45 1.00     1417     2478
dataset4[3]       0.13      0.46    -0.77     1.01 1.00     1528     2632
dataset4[4]      -0.21      0.56    -1.31     0.89 1.00     1356     2396
dataset4[5]      -0.84      0.64    -2.14     0.38 1.00     1366     2369
dataset4[6]       0.43      0.63    -0.78     1.70 1.00     1492     1888
dataset4[7]       0.40      0.43    -0.45     1.26 1.00     1785     2788
dataset4[8]      -0.39      0.49    -1.36     0.53 1.00     1743     2074
dataset4[9]       0.12      0.57    -0.99     1.22 1.00     1742     2377
dataset4[10]     -0.18      0.84    -1.83     1.45 1.01     1097     1429

Samples were drawn using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
  1. Adjecent-category model without category-specific effects (to check if differences between model 2 and 3 are not due to different classes of ordinal models):
ord.4 <- brm(
  value ~ 1 + dataset +
    (1|sub) + (1|itemnr),
  data  = DF.test,  
  family = acat("logit"),
  file = 'ord.4~category2.RDS'
) 

Get summary and marginal effects: #should add 1|itemnr and 1|sub

summary(ord.4) #prob = .99  for 99 credible intervals
 Family: acat 
  Links: mu = logit; disc = identity 
Formula: value ~ 1 + dataset + (1 | sub) + (1 | itemnr) 
   Data: DF.test (Number of observations: 1616) 
Samples: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup samples = 4000

Group-Level Effects: 
~itemnr (Number of levels: 15) 
              Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(Intercept)     0.55      0.12     0.37     0.85 1.00      591      869

~sub (Number of levels: 108) 
              Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(Intercept)     0.27      0.03     0.22     0.32 1.00     1223     2264

Population-Level Effects: 
              Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept[1]      0.24      0.18    -0.11     0.60 1.01      243      501
Intercept[2]      0.21      0.19    -0.18     0.58 1.01      276      570
Intercept[3]      0.06      0.20    -0.34     0.48 1.01      297      661
Intercept[4]      0.54      0.21     0.13     0.96 1.01      335      746
Intercept[5]     -0.18      0.22    -0.62     0.25 1.01      335      808
Intercept[6]      0.47      0.22     0.06     0.90 1.01      379      705
Intercept[7]      0.20      0.22    -0.23     0.62 1.01      322      635
Intercept[8]      0.49      0.21     0.08     0.90 1.01      349      609
Intercept[9]      1.36      0.23     0.91     1.83 1.01      393     1067
Intercept[10]     0.23      0.23    -0.25     0.68 1.00      367      995
dataset2          0.08      0.07    -0.07     0.22 1.00      759     1419
dataset3         -0.13      0.08    -0.29     0.04 1.01      797     1199
dataset4         -0.03      0.08    -0.19     0.13 1.01      755     1456

Samples were drawn using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
conditional_effects(ord.4, "dataset", categorical = TRUE)

  1. Unequal variances model:
ord.5 <- brm(
  formula = bf(value ~ 1 + dataset) +
    lf(disc ~ 0 + dataset, cmc = FALSE),
  data = DF.test,
  family  = cumulative("logit"),
  file = 'ord.5~control.RDS'
) 

Get summary and marginal effects:

summary(ord.5) #prob = .99  for 99 credible intervals
 Family: cumulative 
  Links: mu = logit; disc = log 
Formula: value ~ 1 + dataset 
         disc ~ 0 + dataset
   Data: DF.test (Number of observations: 1616) 
Samples: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup samples = 4000

Population-Level Effects: 
              Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept[1]     -0.73      0.10    -0.93    -0.53 1.00     1834     2599
Intercept[2]     -0.15      0.09    -0.33     0.03 1.00     2488     2795
Intercept[3]      0.17      0.09    -0.00     0.34 1.00     2667     3048
Intercept[4]      0.44      0.09     0.26     0.61 1.00     2701     3031
Intercept[5]      0.61      0.09     0.43     0.79 1.00     2626     2935
Intercept[6]      0.87      0.10     0.68     1.06 1.00     2441     2828
Intercept[7]      1.11      0.10     0.91     1.31 1.00     2217     2914
Intercept[8]      1.47      0.11     1.25     1.70 1.00     1978     2784
Intercept[9]      2.02      0.13     1.77     2.29 1.00     1627     2340
Intercept[10]     2.45      0.16     2.15     2.76 1.00     1586     2331
dataset2          0.32      0.10     0.13     0.52 1.00     2594     2944
dataset3         -0.11      0.12    -0.35     0.13 1.00     2696     3110
dataset4         -0.03      0.13    -0.28     0.21 1.00     2906     2956
disc_dataset2     0.38      0.07     0.25     0.51 1.00     1372     2188
disc_dataset3     0.19      0.08     0.03     0.35 1.00     1588     2452
disc_dataset4     0.06      0.08    -0.11     0.22 1.00     1826     2651

Samples were drawn using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
conditional_effects(ord.5, "dataset", categorical = TRUE)

  1. Model comparison:
modelC1 
Output of model 'ord.1':

Computed from 4000 by 1616 log-likelihood matrix
------
Monte Carlo SE of elpd_loo is 0.0.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Output of model 'ord.2':

Computed from 4000 by 1616 log-likelihood matrix
------
Monte Carlo SE of elpd_loo is 0.1.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Output of model 'ord.3':

Computed from 4000 by 1616 log-likelihood matrix
------
Monte Carlo SE of elpd_loo is 0.2.

Pareto k diagnostic values:
                         Count Pct.    Min. n_eff
(-Inf, 0.5]   (good)     1614  99.9%   728       
 (0.5, 0.7]   (ok)          2   0.1%   1193      
   (0.7, 1]   (bad)         0   0.0%   <NA>      
   (1, Inf)   (very bad)    0   0.0%   <NA>      

All Pareto k estimates are ok (k < 0.7).
See help('pareto-k-diagnostic') for details.

Output of model 'ord.4':

Computed from 4000 by 1616 log-likelihood matrix
------
Monte Carlo SE of elpd_loo is 0.2.

Pareto k diagnostic values:
                         Count Pct.    Min. n_eff
(-Inf, 0.5]   (good)     1615  99.9%   405       
 (0.5, 0.7]   (ok)          1   0.1%   2379      
   (0.7, 1]   (bad)         0   0.0%   <NA>      
   (1, Inf)   (very bad)    0   0.0%   <NA>      

All Pareto k estimates are ok (k < 0.7).
See help('pareto-k-diagnostic') for details.

Output of model 'ord.5':

Computed from 4000 by 1616 log-likelihood matrix
------
Monte Carlo SE of elpd_loo is 0.1.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Model comparisons:
      elpd_diff se_diff
ord.2    0.0       0.0 
ord.3   -1.5      16.5 
ord.4  -46.0      10.6 
ord.5 -631.9      28.5 
ord.1 -648.4      27.2 
  1. Rerun winning model excluding the participants that completed the incorrect IDAQ version:
cumulativemodelfit(value ~ 1, data=DF.test)
         flexible equidistant
logit   -2975.673   -3023.229
probit  -2975.673   -3014.616
cloglog -2975.673   -3023.926
cauchit -2975.673   -3014.616

The best link function is probit with a equidistant threshold (logLik -2975.673)
  1. Model 2 while excluding these participants:
ord.2E <- brm(
  value ~ 1 + dataset +
    (1|sub) + (1|itemnr),   
  data  = DF.test,  
  family = cumulative(link = "probit", threshold="equidistant"),
  file = 'ord.2E~random.RDS'
) 

Get summary and marginal effects:

summary(ord.2E) #prob = .99  for 99 credible intervals
conditional_effects(ord.2E, "dataset", categorical = TRUE)
  1. Model 3 while excluding these participants (no convergence):
ord.3E <- brm(
  value ~ 1 + cs(dataset) +
    (cs(1)|sub) + (cs(1)|itemnr),
  data  = DF.test,  
  family = acat(link = "probit", threshold="equidistant"),
  file = 'ord.3E~category.RDS'
)  

summary(ord.3E)

Final output (Table S7):

# load required packages
library(sjPlot)
library(insight)
library(httr)

tab_model(
  ord.2,ord.3,ord.2E,
  show.se = FALSE,
  #collapse.se = TRUE,
  #pred.labels = c("Intercept", "linear predictor", "quadratic predictor"),
  dv.labels = c("cumulative ordinal model", "cumulative ordinal model (excluding 16 participants)"),
  show.obs=FALSE
)

5.5 IDAQ per subject

Calculate the IDAQ per subject:

DF.idaq <- DF.idaq %>%
  group_by(sub,dataset, scale) %>%
  summarise(score = sum(value, na.rm = TRUE)) %>%
  ungroup()%>%
  mutate_at(vars(-score),as.factor)
`summarise()` regrouping output by 'sub', 'dataset' (override with `.groups` argument)

5.6 Visualise the scores

Visualise the scores across the datasets and scales (Figure S1):

source("R_rainclouds.R") #/Volumes/Project0255/code
source("summarySE.R")
theme_set(theme_classic(base_size = 15)) 

idaq_sum <- summarySEwithin(DF.idaq, measurevar="score", betweenvars="dataset", withinvars= "scale", idvar="sub")

FS1 <- DF.idaq %>%
  group_by(sub,dataset, scale) %>%
  ggplot(.,aes(x=dataset,y=score,fill=dataset, group = dataset))+
  geom_flat_violin(position=position_nudge(x = .2, y = 0),adjust =2, trim = FALSE, alpha = .75, colour = "Black") +
  geom_point(aes(colour = dataset), position=position_jitter(width = .05), size = .5, shape = 21, colour = "Black") +
  geom_boxplot(aes(x=dataset,y=score),position=position_nudge(x = .1, y = 0),outlier.shape = NA, alpha = .5, width = .1, colour = "black") + 
  geom_point(data = idaq_sum, aes(x = dataset, y = score), position = position_nudge(.3), colour = "BLACK")+
  geom_errorbar(data = idaq_sum, aes(x=dataset,y=score, ymin = score-ci, ymax = score+ci), position=position_nudge(x = .3, y = 0), width = .05)+
  scale_fill_brewer(palette = "Greys") +
  scale_colour_brewer(palette = "Greys") +
  ylab(paste("score (0-150)")) + 
  ggtitle(paste("IDAQ scores across datasets")) +
  theme(legend.position="none") +
  facet_wrap(~scale)
FS1
ggsave("S1.TIFF", plot = FS1, width = 24.7, height = 15.24, units = "cm", dpi = 300)

Visualise the scores for IDAQ scale only (Figure 1A):

idaq_sum <- summarySEwithin(DF.idaq, measurevar="score", withinvars= "scale", idvar="sub")
 
F1A <- DF.idaq %>%
  filter(scale == "IDAQ") %>%
  group_by(sub) %>%
  ggplot(.,aes(x = 1, y=score, fill = "Black"))+
  geom_flat_violin(position=position_nudge(x = .2, y = 0),adjust =2, trim = FALSE, alpha = .75, colour = "Black") +
  geom_point(aes(colour = dataset), position=position_jitter(width = .05), size = .5, shape = 21, colour = "Black") +
  geom_boxplot(aes(x=1,y=score),position=position_nudge(x = .12, y = 0),outlier.shape = NA, alpha = .5, width = .1, colour = "black") + 
  geom_point(data = idaq_sum %>% filter(scale == "IDAQ"), aes(x = 0.95, y = score), position = position_nudge(.3), colour = "BLACK")+
  geom_errorbar(data = idaq_sum %>% filter(scale == "IDAQ"), aes(x=0.95,y=score, ymin = score-ci, ymax = score+ci), position=position_nudge(x = .3, y = 0), width = .05)+
  scale_fill_brewer(palette = "Greys") +
  scale_colour_brewer(palette = "Greys") +
  #theme_classic() + 
  coord_fixed(ratio = 1/90) + 
  ylab(paste("Dispositional anthropomorphism (0-150)")) + 
  #ggtitle(paste("Dispositional anthropomorphism")) +
  theme(legend.position="none") +
  theme(
    axis.title.x = element_blank(),
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank()
      
  )
F1A
ggsave("F1A.TIFF", plot = F1A, width = 24.7, height = 15.24, units = "cm", dpi = 300)

5.7 Median and interquartile range per dataset

Calculate the median IQR per dataset (table S2):

DF.idaq %>%
  #filter(!sub %in%  sub_ex) %>% 
  group_by(sub,dataset, scale) %>%
  summarise(score = sum(score)) %>%
  group_by(scale) %>%
  summarise(median = median(score),
            iqr = IQR(score))
`summarise()` regrouping output by 'sub', 'dataset' (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)

6. fROI results

6.1 Data wrangling

Create function to load the data for the different networks:

library(fs)
library(tidyverse)
roi_extract <- function(datasetno, substart, subend, network, nroi) {
  
  dir_ls(paste("dataset_", datasetno, "/derivatives/roi/", network, sep = ""), regexp = "\\.tsv$") %>% 
    map_dfr(read.delim, sep = "\t", .id = "id", header = FALSE)  %>%
    mutate(dataset = datasetno) %>%
    mutate(network = network) %>%
    mutate(network = str_extract(network, "tom|pain")) %>%
    mutate(id = str_extract(id, "dmpfc|mmpfc|vmpfc|ltpj|rtpj|prec|amcc|lmfg|rmfg|ls2|rs2|linsula|rinsula")) %>%
    rename(roi = id, contrast = V1) %>%
    mutate(sub = rep(substart:subend, times=nroi, each=1)) %>%
    select(5,3,4,1:2)
} 

Load the data for the Theory-of-Mind network:

DF.d1 <- roi_extract(1, 101, 129, "tom", 6)
DF.d2.a <- roi_extract(2, 201, 202, "tom/201_202", 6)
DF.d2.b <- roi_extract(2, 203, 235, "tom", 6)
DF.d3 <- roi_extract(3, 301, 322, "tom", 6)
DF.d4 <- roi_extract(4, 401, 422, "tom", 6)

DF.temp <- bind_rows(DF.d1, DF.d2.a, DF.d2.b, DF.d3, DF.d4) 

Load the data for the Pain Matrix:

DF.d1 <- roi_extract(1, 101, 129, "pain", 7)
DF.d2.a <- roi_extract(2, 201, 202, "pain/201_202/", 7)
DF.d2.b <- roi_extract(2, 203, 235, "pain", 7)
DF.d3 <- roi_extract(3, 301, 322, "pain", 7)
DF.d4 <- roi_extract(4, 401, 422, "pain", 7)

DF.roi <- bind_rows(DF.temp, DF.d1, DF.d2.a, DF.d2.b, DF.d3, DF.d4)

rm(DF.d1, DF.d2.a, DF.d2.b, DF.d3, DF.d4, DF.temp)

Reorder ROI names for plots:

order <- c("rtpj", "ltpj", "prec", "vmpfc","mmpfc","dmpfc", "rs2", "ls2", "rinsula", "linsula", "rmfg", "lmfg", "amcc")  

DF.roi <- DF.roi %>%
  mutate_at(vars(-contrast),as.factor) %>%
  group_by(sub, dataset) %>%
  mutate(roi = fct_relevel(roi, order))

6.2 Theory-of-Mind network activation across datasets:

Plot the ToM activity across regions and datasets (Figure S2):

source("R_rainclouds.R") #/Volumes/Project0255/code
source("summarySE.R")
theme_set(theme_classic(base_size = 15)) 

roi_sum <- summarySEwithin(DF.roi, measurevar="contrast", betweenvars="dataset", withinvars= c("roi","network"), idvar="sub")

FS2 <- DF.roi %>%
  filter(network == "tom") %>%
  ggplot(.,aes(x=roi,y=contrast,fill=roi))+
  geom_hline(yintercept = 0, color = "grey", linetype = 2) +
  geom_flat_violin(position=position_nudge(x = .2, y = 0),adjust =2, trim = FALSE, colour = "Black") +
  geom_point(aes(colour = roi, fill = roi), position=position_jitter(width = .05), size = .5, shape = 21, colour = "Black") +
  geom_boxplot(aes(x=roi,y=contrast),position=position_nudge(x = .1, y = 0),outlier.shape = NA, alpha = .5, width = .1, colour = "black") + 
  geom_point(data = roi_sum %>% filter(network == "tom"), aes(x = roi, y = contrast), position = position_nudge(.3), colour = "BLACK")+
  geom_errorbar(data = roi_sum %>% filter(network == "tom"), aes(x=roi,y=contrast, ymin = contrast-ci, ymax = contrast+ci), position=position_nudge(x = .3, y = 0), width = .05)+
  #theme_classic() + 
  ylab(paste("contrast estimates (mental > pain)")) + 
  scale_fill_brewer(palette = "Blues") +
  scale_colour_brewer(palette = "Blues") + 
  ggtitle(paste("Theory-of-Mind network contrasts estimates across datasets and regions")) + 
  theme(legend.position="none") +
  facet_wrap(~dataset) 
FS2

ggsave("S2.TIFF", plot = FS2, width = 24.7, height = 15.24, units = "cm", dpi = 300)

Plot the ToM activity across regions (Figure 1C):

source("R_rainclouds.R") #/Volumes/Project0255/code
source("summarySE.R")
theme_set(theme_classic(base_size = 15)) 

roi_sum <- summarySEwithin(DF.roi, measurevar="contrast", withinvars= c("roi","network"), idvar="sub")

F1C <- DF.roi %>%
  filter(network == "tom") %>%
  ggplot(.,aes(x=roi,y=contrast,fill=roi))+
  geom_hline(yintercept = 0, color = "grey", linetype = 2) +
  geom_flat_violin(position=position_nudge(x = .2, y = 0),adjust =2, trim = FALSE, colour = "Black") +
  geom_point(aes(colour = roi, fill = roi), position=position_jitter(width = .05), size = .5, shape = 21, colour = "Black") +
  geom_boxplot(aes(x=roi,y=contrast),position=position_nudge(x = .1, y = 0),outlier.shape = NA, alpha = .5, width = .1, colour = "black") + 
  geom_point(data = roi_sum %>% filter(network == "tom"), aes(x = roi, y = contrast), position = position_nudge(.3), colour = "BLACK")+
  geom_errorbar(data = roi_sum %>% filter(network == "tom"), aes(x=roi,y=contrast, ymin = contrast-ci, ymax = contrast+ci), position=position_nudge(x = .3, y = 0), width = .05)+
  #theme_classic() + 
  ylab(paste("Theory-of-Mind network activation")) + 
  scale_fill_brewer(palette = "Blues") +
  scale_colour_brewer(palette = "Blues") + 
  #ggtitle(paste("Theory-of-Mind network contrasts estimates across datasets and regions")) + 
  theme(legend.position="none") 

F1C

ggsave("F1C.TIFF", plot = F1C, width = 24.7, height = 15.24, units = "cm", dpi = 300)

6.3 Differences in ToM activation between datasets:

Test if for potential differences between datasets and rois:

p
$roi
NA
# load required packages
library(sjPlot)
#refugeeswelcome

6.4 Pain Matrix activation across datasets

Plot the Pain Matrix activity across regions and datasets (Figure S3):

FS3 <- DF.roi %>%
  filter(network == "pain") %>%
  ggplot(.,aes(x=roi,y=contrast,fill=roi))+
  geom_hline(yintercept = 0, color = "grey", linetype = 2) +
  geom_flat_violin(position=position_nudge(x = .2, y = 0),adjust =2, trim = FALSE, colour = "Black") +
  geom_point(aes(colour = roi, fill = roi), position=position_jitter(width = .05), size = .5, shape = 21, colour = "Black") +
  geom_boxplot(aes(x=roi,y=contrast),position=position_nudge(x = .1, y = 0),outlier.shape = NA, alpha = .5, width = .1, colour = "black") +
  geom_point(data = roi_sum %>% filter(network == "pain"), aes(x = roi, y = contrast), position = position_nudge(.3), colour = "BLACK")+
  geom_errorbar(data = roi_sum %>% filter(network == "pain"), aes(x=roi,y=contrast, ymin = contrast-ci, ymax = contrast+ci), position=position_nudge(x = .3, y = 0), width = .05)+
  #theme_classic() + 
  ylab(paste("contrast estimates (pain > mental)")) + 
  scale_fill_brewer(palette = "Reds") +
  scale_colour_brewer(palette = "Reds") + 
  ggtitle(paste("Pain Matrix contrasts estimates across datasets and regions")) + 
  theme(legend.position="none") +
  facet_wrap(~dataset)
FS3
ggsave("S3.TIFF", plot = FS3, width = 24.7, height = 15.24, units = "cm", dpi = 300)

6.5 Differences in Pain Matrix activation between datasets:

Test if for potential differences between datasets and rois:

pain.compare <- brm(
  formula = contrast ~ roi * dataset,
  data = DF.roi %>% filter(network == "pain"),
  #family  = cumulative("logit"),
  file = 'pain.compare.RDS'
) 

summary(pain.compare)
 Family: gaussian 
  Links: mu = identity; sigma = identity 
Formula: contrast ~ roi * dataset 
   Data: DF.roi %>% filter(network == "pain") (Number of observations: 756) 
Samples: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup samples = 4000

Population-Level Effects: 
                    Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept               0.73      0.07     0.59     0.86 1.00     1162     1832
roils2                 -0.14      0.09    -0.32     0.05 1.00     1699     2755
roirinsula             -0.42      0.10    -0.61    -0.24 1.00     1592     2578
roilinsula             -0.44      0.10    -0.63    -0.26 1.00     1428     2394
roirmfg                -0.53      0.10    -0.72    -0.34 1.00     1480     2705
roilmfg                -0.35      0.10    -0.54    -0.17 1.00     1735     2682
roiamcc                -0.54      0.10    -0.72    -0.35 1.00     1508     2540
dataset2                0.38      0.09     0.19     0.56 1.00     1645     2137
dataset3               -0.11      0.11    -0.32     0.09 1.00     1224     2211
dataset4               -0.08      0.10    -0.29     0.12 1.00     1646     2118
roils2:dataset2        -0.04      0.13    -0.29     0.21 1.00     2224     3033
roirinsula:dataset2    -0.24      0.13    -0.49     0.01 1.00     2080     2455
roilinsula:dataset2    -0.12      0.13    -0.38     0.14 1.00     2196     3008
roirmfg:dataset2       -0.35      0.13    -0.61    -0.09 1.00     2097     2840
roilmfg:dataset2       -0.53      0.13    -0.79    -0.27 1.00     2249     2796
roiamcc:dataset2       -0.12      0.13    -0.37     0.13 1.00     2070     3017
roils2:dataset3         0.05      0.15    -0.24     0.34 1.00     1786     2526
roirinsula:dataset3    -0.01      0.15    -0.29     0.28 1.00     1711     2230
roilinsula:dataset3     0.06      0.15    -0.22     0.35 1.00     1485     2966
roirmfg:dataset3        0.05      0.15    -0.24     0.34 1.00     1734     2535
roilmfg:dataset3       -0.04      0.15    -0.33     0.25 1.00     1881     2503
roiamcc:dataset3        0.22      0.15    -0.07     0.51 1.00     1839     2592
roils2:dataset4         0.06      0.14    -0.22     0.33 1.00     2078     2870
roirinsula:dataset4     0.07      0.15    -0.21     0.35 1.00     2141     2734
roilinsula:dataset4     0.18      0.15    -0.10     0.47 1.00     2028     2931
roirmfg:dataset4        0.07      0.15    -0.22     0.36 1.00     2079     2366
roilmfg:dataset4       -0.17      0.15    -0.45     0.13 1.00     2059     2524
roiamcc:dataset4        0.24      0.15    -0.04     0.53 1.00     2147     2756

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sigma     0.36      0.01     0.35     0.38 1.00     5135     3017

Samples were drawn using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
plot(pain.compare)

conditional_effects(pain.compare)

# load required packages
library(sjPlot)
library(insight)
library(httr)

tab_model(
  pain.compare,
  show.se = FALSE,
  #collapse.se = TRUE,
  #pred.labels = c("Intercept", "linear predictor", "quadratic predictor"),
  #dv.labels = c("cumulative ordinal model", "cumulative ordinal model (excluding 16 participants)"),
  show.obs=FALSE
)

6.6 Combine IDAQ scores and ROI data:

Create one DF:

DF.roi <- DF.idaq %>% 
  group_by(sub,dataset, scale) %>%
  ungroup() %>% 
  left_join(DF.roi, DF.idaq, by = c("sub","dataset"), keep = FALSE) %>%
  pivot_wider(names_from=scale, values_from = score) #

Center the variables for the formal analysis:

DF.roi$cent_IDAQNA <- scale(DF.roi$IDAQNA, scale = TRUE)
DF.roi$cent_IDAQ <- scale(DF.roi$IDAQ, scale = TRUE)
DF.roi <- DF.roi %>% group_by(roi) %>% mutate(cent_contrast = scale(contrast, scale =TRUE)) #scale per roi (analyses are done per roi)

7. IDAQ scores and ToM activity

7.1 Plot ToM and IDAQ

Create scatterplots with linear and non-linear lines for ToM network:

library(patchwork)
theme_set(theme_classic(base_size = 15)) 

F1D <- DF.roi %>%
  filter(network == "tom") %>%
  ggplot(aes(x=cent_IDAQ, y=cent_contrast)) +
  geom_point(alpha=0.5,show.legend = FALSE) +
  geom_smooth(method="lm", formula=y ~ x, se=TRUE, show.legend = FALSE, colour="#0072B2") +
  geom_smooth(method="lm", formula=y ~ x+ I(x^2), se=TRUE, show.legend=FALSE, colour = "#D55E00") +
  coord_fixed(ratio = 1/1) +
  labs(
    x="Dispositional anthropomorphism",
    y="Theory-of-Mind network activation"
  ) #+ theme_classic()

F1D 

ggsave("F1D.TIFF", plot = F1D, width = 24.7, height = 15.24, units = "cm", dpi = 300)

Create scatterplots with linear and non-linear lines for individual regions of ToM network:

F1E <- DF.roi %>%
  filter(network == "tom") %>%
  ggplot(aes(x=cent_IDAQ, y=cent_contrast)) +
  geom_point(alpha=0.5,show.legend = FALSE) +
  geom_smooth(method="lm", formula=y ~ x, se=TRUE, show.legend = FALSE, colour="#0072B2") +
  geom_smooth(method="lm", formula=y ~ x+ I(x^2), se=TRUE, show.legend=FALSE, colour = "#D55E00") +
  coord_fixed(ratio = 1/1) +
  facet_wrap(~roi, ncol = 6) +
  labs(
    x="Dispositional anthropomorphism",
    y="Theory-of-Mind network activation"
  ) + theme_classic() 

F1E

ggsave("F1E.TIFF", plot = F1E, width = 24.7, height = 15.24, units = "cm", dpi = 300)

7.2 Create a function for the Bayesian regression models:

For the formal analysis we will test a linear and quadratic relationship between IDAQ and ToM network activity:

DF.roi$cent_IDAQ2 <- DF.roi$cent_IDAQ^2

We run the models with uninformative (default) priors and create a function to run it for each region separately:

reg_model <- function(region){
  brm(formula = cent_contrast ~ cent_IDAQ + cent_IDAQ2,
      data = DF.roi %>% filter(roi == region),
      family = gaussian,
      chains = 4,
      iter = 4000,
      seed = 42, #so the model is reproducible
      file = paste0(region, ".RDS"))
}

7.3 Run the ToM regression models:

Run the models for the ToM network first. It will load the model if it is already calculated:

library("brms")
rtpj <- reg_model("rtpj")
ltpj <- reg_model("ltpj")
prec <- reg_model("prec")
vmpfc <- reg_model("vmpfc")
mmpfc <- reg_model("mmpfc")
dmpfc <- reg_model("dmpfc")

Get the summaries (verbatim, run individually):

summary(rtpj)
 Family: gaussian 
  Links: mu = identity; sigma = identity 
Formula: cent_contrast ~ cent_IDAQ + cent_IDAQ2 
   Data: DF.roi %>% filter(roi == region) (Number of observations: 108) 
Samples: 4 chains, each with iter = 4000; warmup = 2000; thin = 1;
         total post-warmup samples = 8000

Population-Level Effects: 
           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept      0.03      0.12    -0.20     0.27 1.00     8407     6013
cent_IDAQ     -0.05      0.10    -0.24     0.15 1.00     8721     6323
cent_IDAQ2    -0.03      0.07    -0.17     0.10 1.00     9151     5801

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sigma     1.02      0.07     0.90     1.17 1.00     7654     5451

Samples were drawn using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).

7.4 ToM model output:

Use sjPlot to create html tables following procedure outlined here:

# load required packages
library(sjPlot)
library(insight)
library(httr)

tab_model(
  rtpj,ltpj,prec,vmpfc,mmpfc,dmpfc,
  show.se = TRUE,
  #collapse.se = TRUE,
  pred.labels = c("Intercept", "linear predictor", "quadratic predictor"),
  dv.labels = c("rtpj", "ltpj","prec","vmpfc","mmpfc","dmpfc"),
  show.obs=FALSE
)

7.5 Posterior plots:

Create plots based on this tutorial:

library(tidyverse)
tom_combined <- bind_rows("rtpj" = as_tibble(as.mcmc(rtpj,  pars = c("b_cent_IDAQ", "b_cent_IDAQ2"), combine_chains = TRUE)),
                          "ltpj" = as_tibble(as.mcmc(ltpj, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
                          "prec" = as_tibble(as.mcmc(prec, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
                          "vmpfc" = as_tibble(as.mcmc(vmpfc, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
                          "mmpfc" = as_tibble(as.mcmc(mmpfc, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
                          "dmpfc" = as_tibble(as.mcmc(dmpfc, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
                          .id = "roi")

order <- c("rtpj", "ltpj", "prec", "vmpfc","mmpfc","dmpfc", "rs2", "ls2", "rinsula", "linsula", "rmfg", "lmfg", "amcc")  

tom_combined <- tom_combined %>%
  rename(linear = b_cent_IDAQ, quadratic = b_cent_IDAQ2) %>%
  pivot_longer(c("linear", "quadratic"),names_to = "varIDAQ") %>%
  mutate(roi = fct_relevel(roi, order[1:6]))

Plot the distributions:

F2 <- tom_combined %>%
  mutate_at(vars(-value),as.factor) %>%
  rename(predictor = varIDAQ) %>%
  ggplot(., aes(value, fill = predictor)) +
  geom_density(alpha = .5)+
  geom_vline(xintercept = 0, color = "black", linetype = 2) +
  ggtitle(paste("Posterior distributions for the Theory-of-Mind network")) + 
  facet_wrap(~roi, ncol =1) +
  coord_fixed(ratio = 1/40) +
  theme_classic(base_size = 8) +
  theme(strip.background = element_blank()) +
  scale_fill_manual(values=c("#0072B2", "#D55E00"))+ 
  theme(axis.text.y = element_blank())
F2

ggsave("F2.TIFF", plot = F2, width = 24.7, height = 15.24, units = "cm", dpi = 300)

8. IDAQ scores and Pain Matrix activity

8.1 Plot Pain Matrix and IDAQ

Create scatterplots with linear and non-linear lines for the Pain Matrix:

S4 <- DF.roi %>%
  filter(network == "pain") %>%
  ggplot(aes(x=cent_IDAQ, y=cent_contrast)) +
  geom_point(alpha=0.5,show.legend = FALSE) +
  geom_smooth(method="lm", formula=y ~ x, se=TRUE, show.legend = FALSE, colour="#0072B2") +
  geom_smooth(method="lm", formula=y ~ x+ I(x^2), se=TRUE, show.legend=FALSE, colour = "#D55E00") +
  #coord_fixed(ratio = 25/1) +
  labs(
    x="IDAQ score",
    y="contrast (pain vs mental)"
  ) + theme_classic()

S4 

ggsave("S4.TIFF", plot = S4, width = 24.7, height = 15.24, units = "cm", dpi = 300)

Create scatterplots with linear and non-linear lines for individual regions of the Pain Matrix:

S5 <- DF.roi %>%
  filter(network == "pain") %>%
  ggplot(aes(x=cent_IDAQ, y=cent_contrast)) +
  geom_point(alpha=0.5,show.legend = FALSE) +
  geom_smooth(method="lm", formula=y ~ x, se=TRUE, show.legend = FALSE, colour="#0072B2") +
  geom_smooth(method="lm", formula=y ~ x+ I(x^2), se=TRUE, show.legend=FALSE, colour = "#D55E00") +
  #coord_fixed(ratio = 25/1) +
  labs(
    x="IDAQ score",
    y="contrast (pain vs mental)"
  ) + theme_classic() +
  facet_wrap(~roi, nrow = 2)

S5 

ggsave("S5.TIFF", plot = S5, width = 24.7, height = 15.24, units = "cm", dpi = 300)

8.2 Regression models for the Pain Matrix:

Run the models for the Pain Matrix (control network). It will load the model if it is already calculated:

rs2 <- reg_model("rs2")
ls2 <- reg_model("ls2")
rinsula <- reg_model("rinsula")
linsula <- reg_model("linsula")
rmfg <- reg_model("rmfg")
lmfg <- reg_model("lmfg")
amcc <- reg_model("amcc")

Get the summaries (verbatim, run individually):

summary(rs2)
summary(ls2)
summary(rinsula)
summary(linsula)
summary(rmfg)
summary(lmfg)
summary(amcc)

8.3 Pain Matrix model output:

Use sjPlot to create html tables following procedure outlined here:

tab_model(
  rs2,ls2,rinsula,linsula,rmfg,lmfg,amcc,
  show.se = TRUE,
  #collapse.se = TRUE,
  pred.labels = c("Intercept", "linear predictor", "quadratic predictor"),
  dv.labels = c("rs2","ls2","rinsula","linsula","rmfg","lmfg","amcc"),
  show.obs=FALSE
)

8.4 Posterior plots:

Create plots based on this tutorial:

pain_combined <- bind_rows("rs2" = as_tibble(as.mcmc(rs2,  pars = c("b_cent_IDAQ", "b_cent_IDAQ2"), combine_chains = TRUE)),
                          "ls2" = as_tibble(as.mcmc(ls2, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
                          "rinsula" = as_tibble(as.mcmc(rinsula, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
                          "linsula" = as_tibble(as.mcmc(linsula, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
                          "rmfg" = as_tibble(as.mcmc(rmfg, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
                          "lmfg" = as_tibble(as.mcmc(lmfg, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
                          "amcc" = as_tibble(as.mcmc(amcc, pars = c("b_cent_IDAQ", "b_cent_IDAQ2"),combine_chains = TRUE)),
                          .id = "roi")

pain_combined <- pain_combined %>%
  rename(linear = b_cent_IDAQ, quadratic = b_cent_IDAQ2) %>%
  pivot_longer(c("linear", "quadratic"),names_to = "varIDAQ") %>%
  mutate(roi = fct_relevel(roi, order[7:13]))

Plot the distributions:

S6 <- pain_combined %>%
  mutate_at(vars(-value),as.factor) %>%
  rename(predictor = varIDAQ) %>%
  ggplot(., aes(value, fill = predictor)) +
  geom_density(alpha = .5)+
  geom_vline(xintercept = 0, color = "black", linetype = 2) +
  ggtitle(paste("Posterior distributions for the Pain Matrix")) + 
  facet_wrap(~roi, ncol =1) +
  coord_fixed(ratio = 1/40) +
  theme_classic(base_size = 8) +
  theme(strip.background = element_blank()) +
  scale_fill_manual(values=c("#0072B2", "#D55E00"))
#theme(axis.text.y = element_blank())

S6 

ggsave("S6.TIFF", plot = S6, width = 24.7, height = 15.24, units = "cm", dpi = 300)

9 One model across the networks

9.1 Theory-of-Mind:

All ToM regions combined:

tom <- brm(formula = cent_contrast ~ cent_IDAQ + cent_IDAQ2,
      data = DF.roi %>% filter(network == "tom"),
      family = gaussian,
      chains = 4,
      iter = 4000,
      seed = 42, #so the model is reproducible
      file = "tom.RDS")

Summary:

summary(tom)

9.2 Pain Matrix:

All ToM regions combined:

pain <- brm(formula = cent_contrast ~ cent_IDAQ + cent_IDAQ2,
      data = DF.roi %>% filter(network == "pain"),
      family = gaussian,
      chains = 4,
      iter = 4000,
      seed = 42, #so the model is reproducible
      file = "pain.RDS")

Summary:

summary(pain)

9.3 Posterior plots for the two networks:

tab_model(
  tom, pain,
  show.se = TRUE,
  #collapse.se = TRUE,
  pred.labels = c("Intercept", "linear predictor", "quadratic predictor"),
  dv.labels = c("tom","pain"),
  show.obs=FALSE
)

9.4 Posterior plots for the two networks:

tom_all <- bind_rows("all" = as_tibble(as.mcmc(tom,  pars = c("b_cent_IDAQ", "b_cent_IDAQ2"), combine_chains = TRUE), .id = "network")  %>%
                        rename(linear = b_cent_IDAQ, quadratic = b_cent_IDAQ2) %>%
                        pivot_longer(c("linear", "quadratic"),names_to = "varIDAQ") %>%
                        mutate(network = "tom"))

pain_all <- bind_rows("all" = as_tibble(as.mcmc(pain,  pars = c("b_cent_IDAQ", "b_cent_IDAQ2"), combine_chains = TRUE), .id = "network")  %>%
                        rename(linear = b_cent_IDAQ, quadratic = b_cent_IDAQ2) %>%
                        pivot_longer(c("linear", "quadratic"),names_to = "varIDAQ") %>%
                        mutate(network = "pain"))

tom_all %>% bind_rows(., pain_all) %>%
  mutate_at(vars(-value),as.factor) %>%
  rename(predictor = varIDAQ) %>%
  ggplot(., aes(value, fill = predictor)) +
  geom_density(alpha = .5)+
  geom_vline(xintercept = 0, color = "black", linetype = 2) +
  ggtitle(paste("Posterior distributions across the two networks")) + 
  facet_wrap(~network) +
  coord_fixed(ratio = 1/40) +
  theme_classic(base_size = 16) +
  scale_fill_manual(values=c("#0072B2", "#D55E00"))+ 
  theme(strip.background = element_blank())

9.5 HDI+ROPE decision rule

library("easystats")

hdi_rope <- function(model){
  rope <- rope_range(model)
  rope_model <- equivalence_test(model, range = rope, ci = 0.95) 
  #rope_model %>% mutate(roi = as.character(model$file))
  plot(rope_model) + theme_classic() + 
    ggtitle(deparse(substitute(model))) + 
    xlim(-0.15,0.15) +  
    theme(axis.title.y = element_blank(), axis.title.x = element_blank()) 
    #scale_fill_manual(values=c("#0072B2", "#D55E00"))
}

hdi_rope(tom) + hdi_rope(pain) + plot_layout(guides = 'collect')  


(hdi_rope(rtpj) / hdi_rope(ltpj) / hdi_rope(prec)) &
(hdi_rope(vmpfc) / hdi_rope(mmpfc) / hdi_rope(dmpfc)) + plot_layout(guides = 'collect')  

(hdi_rope(rtpj) | hdi_rope(ltpj)) /
(hdi_rope(prec) | hdi_rope(vmpfc)) /
(hdi_rope(mmpfc) | hdi_rope(dmpfc)) + plot_layout(guides = 'collect')  

10. Control analyses

##10.1 Theory-of-Mind network Update the models by removing the 16 participants that completed a different version of the IDAQ (1-10). We create a function to do this:


update_model <- function(model_old, region){
  model_new <- update(model_old, newdata = DF.roi %>% filter(roi == region & !sub %in% sub_ex), seed = 41)
  
  m1 <- posterior_summary(model_old)[c("b_cent_IDAQ", "b_cent_IDAQ2") , "Estimate"]
  m2 <- posterior_summary(model_new)[c("b_cent_IDAQ", "b_cent_IDAQ2") , "Estimate"]
  
  tibble(bias = round(100*((m1-m2)/m2), 2), predictor = c("b_cent_IDAQ", "b_cent_IDAQ2"))
}

Calculate the difference (bias) per ToM region:

tab_model(
  rtpj_bias,
  show.se = TRUE,
  #collapse.se = TRUE,
  #pred.labels = c("Intercept", "linear predictor", "quadratic predictor"),
  #dv.labels = c("rtpj", "ltpj","prec","vmpfc","mmpfc","dmpfc"),
  show.obs=FALSE
)
Error in model_info.data.frame(model) : 
  A data frame is no valid object for this function

##10.1 Pain Matrix Calculate the difference (bias) per Pain Matrix region:

rs2_bias <- update_model(rtpj, "rs2")
Error: The following variables are missing in 'data':
'cent_contrast', 'cent_IDAQ', 'cent_IDAQ2'
sessionInfo()
LS0tCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgbnVtYmVyX3NlY3Rpb25zOiBubwogICAgdGhlbWU6IGRlZmF1bHQKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogeWVzCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQojKipBblRocm9NKioKKipFeHBlcmltZW50IDE6IHRlc3RpbmcgdGhlIHJlbGF0aW9uIGJldHdlZW4gZGlzcG9zaXRpb25hbCBhbnRocm9wb21vcnBoaXNtIGFuZCBUaGVvcnktb2YtTWluZCBuZXR3b3JrIGFjdGl2YXRpb24qKiAgCmJ5ICpSdXVkIEhvcnRlbnNpdXMgYW5kIE1pY2hhZWxhIEtlbnQgKFVuaXZlcnNpdHkgb2YgR2xhc2dvdykgLSBKdW5lIDIwMTkgLSAuLi4qCgojIDEuIERldGFpbHMgey50YWJzZXR9CgojIyAxLjEgRGF0YSBkZXNjcmlwdGlvbgoKRGF0YSBvZiB0aGUgVGhlb3J5LW9mLU1pbmQgZnVuY3Rpb25hbCBsb2NhbGlzZXIgYW5kIEluZGl2aWR1YWwgRGlmZmVyZW5jZXMgaW4gQW50aHJvcG9tb3JwaGlzbSBRdWVzdGlvbm5haXJlIGFyZSBmcm9tIGZpdmUgZGlmZmVyZW50IHN0dWRpZXMuCiAgCiBEYXRhc2V0XzE6IEJhbmdvciBJbWFnaW5nIFVuaXQ7IEVNQk9UUzsgKm4qPTI5IChpbmNsdWRpbmcgMSBwaWxvdCBzY2FuKTsgZnVsbCBkYXRhc2V0IGFuZCBwdWJsaWNhdGlvbjogW0Nyb3NzLi4uSG9ydGVuc2l1cyAoMjAxOSkgICBQVFJCXShodHRwczovL3JveWFsc29jaWV0eXB1Ymxpc2hpbmcub3JnL2RvaS8xMC4xMDk4L3JzdGIuMjAxOC4wMDM0KS4gIAogCiBEYXRhc2V0XzI6IENlbnRyZSBmb3IgQ29nbml0aXZlIE5ldXJvSW1hZ2luZzsgU0hBUkVEQk9UUzsgKm4qPTM1IChpbmNsdWRpbmcgMiBwaWxvdCBzY2FucykgcHVibGljYXRpb246IEhvcnRlbnNpdXMgJiBDcm9zcywgaW4gcHJlcGFyYXRpb24uICAKIAogRGF0YXNldF8zOiBDZW50cmUgZm9yIENvZ25pdGl2ZSBOZXVyb0ltYWdpbmc7IFR3byBzdHVkaWVzIHdpdGggdGhlIHNhbWUgcGFyYW1ldGVyczogKm4qPTIyIChpbmNsdWRpbmcgMiBwaWxvdCBzY2FucykuIFNvY2lhbF9HcmFkaWVudF8xOyAqbio9MTAgKHBpbG90IGV4cGVyaW1lbnQpIGFuZCBCT0xEbGlnaHQ7ICpuKj0xMi4gIAogCiBEYXRhc2V0XzQ6IENlbnRyZSBmb3IgQ29nbml0aXZlIE5ldXJvSW1hZ2luZzsgR0FNRUJPVFM7ICpuKj0yMi4gIAoKR2V0IGluZm8gZm9yIHRhYmxlIFMxOgpgYGB7cn0KbGlicmFyeSgidGlkeXZlcnNlIikKCiNsb2FkIG93biBkYXRhCkRGLmRhdGFzZXQxIDwtIHJlYWRfdHN2KGZpbGUgPSAiL1ZvbHVtZXMvUHJvamVjdDAyNTUvZGF0YXNldF8xL3BhcnRpY2lwYW50cy50c3YiKQpERi5kYXRhc2V0MiA8LSByZWFkX3RzdihmaWxlID0gIi9Wb2x1bWVzL1Byb2plY3QwMjU1L2RhdGFzZXRfMi9wYXJ0aWNpcGFudHMudHN2IikKREYuZGF0YXNldDMgPC0gcmVhZF90c3YoZmlsZSA9ICIvVm9sdW1lcy9Qcm9qZWN0MDI1NS9kYXRhc2V0XzMvcGFydGljaXBhbnRzLnRzdiIpCkRGLmRhdGFzZXQ0IDwtIHJlYWRfdHN2KGZpbGUgPSAiL1ZvbHVtZXMvUHJvamVjdDAyNTUvZGF0YXNldF80L3BhcnRpY2lwYW50cy50c3YiKQoKI2NvbWJpbmUgZGF0YQpiaW5kX3Jvd3MoREYuZGF0YXNldDEsIERGLmRhdGFzZXQyLCBERi5kYXRhc2V0MywgIERGLmRhdGFzZXQ0LCAuaWQgPSAiZGF0YXNldCIpICU+JQogIGdyb3VwX2J5KGRhdGFzZXQpICU+JSAKICBzdW1tYXJpc2UobWVhbiA9IG1lYW4oYWdlKSwgCiAgICAgICAgICAgIHNkID0gc2QoYWdlKSkKYmluZF9yb3dzKERGLmRhdGFzZXQxLCBERi5kYXRhc2V0MiwgREYuZGF0YXNldDMsICBERi5kYXRhc2V0NCwgLmlkID0gImRhdGFzZXQiKSAlPiUKICBncm91cF9ieShkYXRhc2V0LCBzZXgpICU+JSAKICB0YWxseSgpCmBgYAoKCiMjIDEuMiBOZXVyb2ltYWdpbmcgcHJvY2VkdXJlCiAKIEFsbCBwYXJ0aWNpcGFudHMgY29tcGxldGVkIGEgVGhlb3J5LW9mLU1pbmQgbG9jYWxpc2VyIChbSmFjb2J5IGV0IGFsLiwgMjAxNl0oaHR0cHM6Ly93d3cuc2NpZW5jZWRpcmVjdC5jb20vc2NpZW5jZS9hcnRpY2xlL3BpaS9TMTA1MzgxMTkxNTAxMDQ3Mik7IFtSaWNoYXJkc29uIGV0IGFsLiAyMDE4XShodHRwczovL3d3dy5uYXR1cmUuY29tL2FydGljbGVzL3M0MTQ2Ny0wMTgtMDMzOTktMikpIGFuZCBhbiBhbmF0b21pY2FsIHNjYW4gZWl0aGVyIGluIHRoZSBzYW1lIHNlc3Npb24gb3IgaW4gdHdvIHNlcGVyYXRlIHNlc3Npb25zLiBEdXJpbmcgdGhlIGxvY2FsaXNlciBwYXJ0aWNpcGFudHMgcGFzc2l2ZWx5IHZpZXdlZCBhIHNob3J0IDUuNiBtaW4gYW5pbWF0ZWQgZmlsbSAoW1BhcnRseSBDbG91ZHldKGh0dHBzOi8vd3d3LnBpeGFyLmNvbS9wYXJ0bHktY2xvdWR5I3BhcnRseS1jbG91ZHktMSkpLiBUaGlzIG1vdmllIGluY2x1ZGVzIHNjZW5lcyBkZXBpY3RpbmcgcGFpbiAoZS5nLiBhbiBhbGxpZ2F0b3IgYml0aW5nIHRoZSBtYWluIGNoYXJhY3RlcikgYW5kIGV2ZW50cyB0aGF0IHRyaWdnZXIgbWVudGFsaXppbmcgKGUuZy4gdGhlIG1haW4gY2hhcmFjdGVyIHJldmVhbGluZyBpdHMgaW50ZW50aW9uKS4gRm9yIGRhdGFzZXRfMyBhbmQgZGF0YXNldF80IGEgZmllbGRtYXAgd2FzIGNvbGxlY3RlZCBhcyB3ZWxsLiBBdCB0aGUgZW5kIG9mIGVhY2ggZXhwZXJpbWVudCBwYXJ0aWNpcGFudHMgY29tcGxldGVkIHRoZSBJbmRpdmlkdWFsIERpZmZlcmVuY2VzIGluIEFudGhyb3BvbW9ycGhpc20gUXVlc3Rpb25uYWlyZSAoSURBUSkgKFtXYXl0eiBldCBhbC4sIDIwMTBdKGh0dHBzOi8vam91cm5hbHMuc2FnZXB1Yi5jb20vZG9pL2Z1bGwvMTAuMTE3Ny8xNzQ1NjkxNjEwMzY5MzM2KSkuIAogCi0gQk9MRDogICAKIERhdGFzZXRfMTogM3gzeDMuNW1tIHZveGVscywgMzIgc2xpY2VzLCByZXBldGl0aW9uIHRpbWUgPSAycywgZWNobyB0aW1lID0gMzBtcyAgCiBEYXRhc2V0XzI6IDNtbSBpc290cm9waWMsIDM3IHNsaWNlcywgVFIgPSAycywgVEUgPSAzMG1zICAKIERhdGFzZXRfMzogMm1tIGlzb3Ryb3BpYywgNjggc2xpY2VzLCBUUiA9IDJzLCBURSA9IDI2bXMgIAogRGF0YXNldF80OiAyLjc1IHggMi43NSB4IDRtbSwgMzIgc2xpY2VzLCBUUiA9IDJzLCBURSA9IDEzIGFuZCAzMW1zICAKIAotIFQxVzogICAKIERhdGFzZXRfMTogMW1tIGlzb3Ryb3BpYyByZXNvbHV0aW9uLCBUUiA9IDEybXMsIFRFID0gMy40NyAvIDUuMTUgLyA2LjgzIC8gOC41MiAvIDEwLjIwbXMgKFNFTlNFKSAgCiBEYXRhc2V0XzIgLSA0OiAxbW0gaXNvdHJvcGljIHJlc29sdXRpb24sIFRSID0gMi4zcywgVEUgPSAyOS42bXMgKEFETkkpICAKIAotIEZpZWxkbWFwczogICAKIERhdGFzZXRfMTogbm8sIHNvIC0tdXNlLXN5bi1zZGMgIAogRGF0YXNldF8yOiBubywgc28gLS11c2Utc3luLXNkYyAgCiBEYXRhc2V0XzM6IHllcyAgCiBEYXRhc2V0XzQ6IHllcyAgCiAKIyMgMS4zIFRvIGRvCi0gcmVtb3ZlIERpY29tcyBhZnRlciBCSURTIGRhdGFzZXQgY3JlYXRpb24gIAotIHJ1biBmb3JtYWwgYW5hbHlzZXMgKEJheWVzaWFuKSAgIAoKTm90ZTogZm9yIHRoZSBjb2RlIGNodW5rIHRoZSBsYW5ndWFnZSBpcyBsaXN0ZWQsIGJ1dCBhbGwgZXhjZXB0IGZvciByLWNodW5rcyBhcmUgZXhlY3V0ZWQgaW4gdGhlIHRlcm1pbmFsICAgCgojIDIuIEJJRFMgZGF0YXNldCB7LnRhYnNldH0KCiMjIDIuMSBDcmVhdGluZyB0aGUgQklEUyBkYXRhc2V0CkZvciB0aGlzIHlvdSBuZWVkIEhldURpQ29udiBbSGV1cmlzdGljIERJQ09NIENvbnZlcnRlcl0oaHR0cHM6Ly9naXRodWIuY29tL25pcHkvaGV1ZGljb252KS4gIApCYXNlZCBvbiB0aGUgdHV0b3JpYWwgYnkgW0ZyYW5rbGluIEZlaW5nb2xkXShodHRwOi8vcmVwcm9kdWNpYmlsaXR5LnN0YW5mb3JkLmVkdS9iaWRzLXR1dG9yaWFsLXNlcmllcy1wYXJ0LTJhLykuCgpEb3dsb2FkIHRoZSBsYXRlc3QgdmVyc2lvbiBvZiBIZXVkaWNvbnYgKHdlIHVzZWQgMC42LjAuZGV2MSk6CmBgYHtiYXNofQpkb2NrZXIgcHVsbCBuaXB5L2hldWRpY29udjpsYXRlc3QKYGBgCgpJZiBvbiB0aGUgR1JJRCBkbzoKYGBge2Jhc2h9CnNpbmd1bGFyaXR5IHB1bGwgZG9ja2VyOi8vbmlweS9oZXVkaWNvbnY6bGF0ZXN0CmBgYAoKQ3JlYXRlIHRoZSBpbmZvIGZpbGUgKGRhdGFzZXRfMiAtIDQpOgpgYGB7YmFzaH0KZG9ja2VyIHJ1biAtLXJtIC1pdCAtdiAvVm9sdW1lcy9Qcm9qZWN0MDI1NS86L2Jhc2UgbmlweS9oZXVkaWNvbnY6bGF0ZXN0IC1kIC9iYXNlL2RhdGFzZXRfMy9zb3VyY2VkYXRhL3N1Yi17c3ViamVjdH0vKi5JTUEgLW8gL2Jhc2UvZGF0YXNldF8zIC1mIGNvbnZlcnRhbGwgLXMgMzE1IC1jIG5vbmUgLS1vdmVyd3JpdGUKYGBgCgpGb3IgZGF0YXNldF8xIHdlIGZpcnN0IG5lZWQgdG8gY29udmVydCB0aGUgLmRjbSBmcm9tIGpwZWctMjAwMCBsb3NzbGVzcyB0byB1bmNvbXByZXNzZWQgZGNtICh0aGFua3MgdG8gTWljaGVsZSBTdmFuZXJhIGZvciB0aGUgY29kZSk6CmBgYHtweXRvbn0KcHl0aG9uMyBjb252ZXJ0X2FsbF9jb21wcmVzc2VkX2RpY29tLnB5CmBgYAoKQ3JlYXRlIHRoZSBpbmZvIGZpbGUgKGRhdGFzZXRfMSk6CmBgYHtiYXNofQpkb2NrZXIgcnVuIC0tcm0gLWl0IC12IC9Wb2x1bWVzL1Byb2plY3QwMjU1LzovYmFzZSBuaXB5L2hldWRpY29udjpsYXRlc3QgLWQgL2Jhc2UvZGF0YXNldF8xL3NvdXJjZWRhdGEvc3ViLXtzdWJqZWN0fS9zZXMte3Nlc3Npb259LyouZGNtIC1vIC9iYXNlL2RhdGFzZXRfMSAtZiBjb252ZXJ0YWxsIC1zIDEyOSAtc3MgMDEgLWMgbm9uZSAtLW92ZXJ3cml0ZQpgYGAKCkdldCB0aGUgaW5mbyBmaWxlOgpgYGB7YmFzaH0KY3AgL1ZvbHVtZXMvUHJvamVjdDAyNTUvY29kZS8uaGV1ZGljb252LzMwMS9pbmZvL2RpY29taW5mby50c3YgL1ZvbHVtZXMvUHJvamVjdDAyNTUvY29kZQpgYGAKCiMjIDIuMiBDcmVhdGUgdGhlIGhldXJpc3RpYyBmaWxlCkNyZWF0ZSB0aGUgZm9sbG93aW5nIHB5dGhvbiBmaWxlIGFuZCBzYXZlIGl0IGluIHRoZSBjb2RlIGZvbGRlci4gVGhlcmUgaXMgb25lIGZ1bmN0aW9uYWwgdGFzayAoZnVuY19tb3ZpZSkgYW5kIG9uZSBhbmF0b21pY2FsICh0MXcpLiBEYXRhc2V0XzMgYW5kIDQgaGF2ZSBhIGZpZWxkIG1hcCBhcyB3ZWxsIChmbWFwX3BoYXNlIGFuZCBmbWFwX21hZ25pdHVkZSkgCgpDcmVhdGUgYSBoZXVyaXN0aWMgdG8gYXV0b21hdGljYWxseSBjb252ZXJ0IHRoZSBmaWxlczoKYGBge3B5dGhvbn0KaW1wb3J0IG9zCmRlZiBjcmVhdGVfa2V5KHRlbXBsYXRlLCBvdXR0eXBlPSgnbmlpLmd6JywpLCBhbm5vdGF0aW9uX2NsYXNzZXM9Tm9uZSk6CiAgICBpZiB0ZW1wbGF0ZSBpcyBOb25lIG9yIG5vdCB0ZW1wbGF0ZToKICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdUZW1wbGF0ZSBtdXN0IGJlIGEgdmFsaWQgZm9ybWF0IHN0cmluZycpCiAgICByZXR1cm4gdGVtcGxhdGUsIG91dHR5cGUsIGFubm90YXRpb25fY2xhc3NlcwpkZWYgaW5mb3RvZGljdChzZXFpbmZvKToKICAgICIiIkhldXJpc3RpYyBldmFsdWF0b3IgZm9yIGRldGVybWluaW5nIHdoaWNoIHJ1bnMgYmVsb25nIHdoZXJlCiAgICBhbGxvd2VkIHRlbXBsYXRlIGZpZWxkcyAtIGZvbGxvdyBweXRob24gc3RyaW5nIG1vZHVsZToKICAgIGl0ZW06IGluZGV4IHdpdGhpbiBjYXRlZ29yeQogICAgc3ViamVjdDogcGFydGljaXBhbnQgaWQKICAgIHNlcWl0ZW06IHJ1biBudW1iZXIgZHVyaW5nIHNjYW5uaW5nCiAgICBzdWJpbmRleDogc3ViIGluZGV4IHdpdGhpbiBncm91cAogICAgc2Vzc2lvbjogc2Vzc2lvbiBpZCAob25seSBmb3IgZGF0YXNldF8xKQogICAgIiIiCiAgICAKICAgIHQxdzEgPSBjcmVhdGVfa2V5KCdzdWIte3N1YmplY3R9L3tzZXNzaW9ufS9hbmF0L3N1Yi17c3ViamVjdH1fe3Nlc3Npb259X1QxdycpCiAgICBmdW5jX21vdmllMSA9IGNyZWF0ZV9rZXkoJ3N1Yi17c3ViamVjdH0ve3Nlc3Npb259L2Z1bmMvc3ViLXtzdWJqZWN0fV97c2Vzc2lvbn1fdGFzay1tb3ZpZV9ib2xkJykKCiAgICB0MXcgPSBjcmVhdGVfa2V5KCdzdWIte3N1YmplY3R9L2FuYXQvc3ViLXtzdWJqZWN0fV9UMXcnKQogICAgZnVuY19tb3ZpZSA9IGNyZWF0ZV9rZXkoJ3N1Yi17c3ViamVjdH0vZnVuYy9zdWIte3N1YmplY3R9X3Rhc2stbW92aWVfYm9sZCcpCiAgICBmdW5jX21vdmllX2VjaG9fMSA9IGNyZWF0ZV9rZXkoJ3N1Yi17c3ViamVjdH0vZnVuYy9zdWIte3N1YmplY3R9X3Rhc2stbW92aWVfZWNoby0xX2JvbGQnKQogICAgZnVuY19tb3ZpZV9lY2hvXzIgPSBjcmVhdGVfa2V5KCdzdWIte3N1YmplY3R9L2Z1bmMvc3ViLXtzdWJqZWN0fV90YXNrLW1vdmllX2VjaG8tMl9ib2xkJykKICAgIGZtYXBfcGhhc2UgPSBjcmVhdGVfa2V5KCdzdWIte3N1YmplY3R9L2ZtYXAvc3ViLXtzdWJqZWN0fV9waGFzZWRpZmYnKQogICAgZm1hcF9tYWduaXR1ZGUgPSBjcmVhdGVfa2V5KCdzdWIte3N1YmplY3R9L2ZtYXAvc3ViLXtzdWJqZWN0fV9tYWduaXR1ZGUnKQogICAgCiAgICBpbmZvID0ge3QxdzE6IFtdLCBmdW5jX21vdmllMTogW10sIHQxdzogW10sIGZ1bmNfbW92aWU6IFtdLCBmbWFwX3BoYXNlOiBbXSwgZm1hcF9tYWduaXR1ZGU6IFtdLAogICAgICAgICAgICBmdW5jX21vdmllX2VjaG9fMTogW10sIGZ1bmNfbW92aWVfZWNob18yOiBbXX0gCiAgICAKICAgIGZvciBpZHgsIHMgaW4gZW51bWVyYXRlKHNlcWluZm8pOgogICAgICAgIGlmICgnVDFXXzFtbV9zYWcgU0VOU0UnIGluIHMucHJvdG9jb2xfbmFtZSk6CiAgICAgICAgICAgIGluZm9bdDF3MV0uYXBwZW5kKHMuc2VyaWVzX2lkKQogICAgICAgIGlmICgnVG9NX1BhcnRseUNsb3VkeSBTRU5TRScgaW4gcy5wcm90b2NvbF9uYW1lKToKICAgICAgICAgICAgaW5mb1tmdW5jX21vdmllMV0uYXBwZW5kKHMuc2VyaWVzX2lkKQogICAgICAgIGlmICgndDFfbXByX25zX3NhZ19pc29fQUROSV8zMmNoJyBpbiBzLnByb3RvY29sX25hbWUpOgogICAgICAgICAgICBpbmZvW3Qxd10uYXBwZW5kKHMuc2VyaWVzX2lkKQogICAgICAgIGlmICgndDFfbXByX25zX3NhZ19QMl9BRE5JXzMyY2gnIGluIHMucHJvdG9jb2xfbmFtZSk6CiAgICAgICAgICAgIGluZm9bdDF3XS5hcHBlbmQocy5zZXJpZXNfaWQpCiAgICAgICAgaWYgKHMuZGltNCA9PSAxNzUpIGFuZCAoJ0ZNUklfTUIyX3AyXzJNTUlTT19UUjJfbW92aWUnIGluIHMucHJvdG9jb2xfbmFtZSk6CiAgICAgICAgICAgIGluZm9bZnVuY19tb3ZpZV0uYXBwZW5kKHMuc2VyaWVzX2lkKQogICAgICAgIGlmIChzLmRpbTQgPT0gMTc1KSBhbmQgKCdGTVJJX01CMl9tb3ZpZV9wMl8yTU1JU09fVFIyJyBpbiBzLnByb3RvY29sX25hbWUpOgogICAgICAgICAgICBpbmZvW2Z1bmNfbW92aWVdLmFwcGVuZChzLnNlcmllc19pZCkKICAgICAgICBpZiAocy5kaW00ID09IDE3MCkgYW5kICgnZXAyZF9Ub01fTG9jJyBpbiBzLnByb3RvY29sX25hbWUpOgogICAgICAgICAgICBpbmZvW2Z1bmNfbW92aWVdLmFwcGVuZChzLnNlcmllc19pZCkKICAgICAgICBpZiAocy5kaW00ID09IDE3NSkgYW5kICgnZXAyZF9Ub01fTG9jJyBpbiBzLnByb3RvY29sX25hbWUpOgogICAgICAgICAgICBpbmZvW2Z1bmNfbW92aWVdLmFwcGVuZChzLnNlcmllc19pZCkKICAgICAgICBpZiAocy5kaW00ID09IDE3NSkgYW5kICgnZXAyZF9Ub01fTG9jX2JvbGRUUjInIGluIHMucHJvdG9jb2xfbmFtZSk6CiAgICAgICAgICAgIGluZm9bZnVuY19tb3ZpZV0uYXBwZW5kKHMuc2VyaWVzX2lkKQogICAgICAgIGlmIChzLlRFID09IDEzKSBhbmQgKCdCUF9lcDJkX211bHRpZWNob18zMmNoX3AzX1RPTScgaW4gcy5wcm90b2NvbF9uYW1lKToKICAgICAgICAgICAgaW5mb1tmdW5jX21vdmllX2VjaG9fMV0uYXBwZW5kKHMuc2VyaWVzX2lkKQogICAgICAgIGlmIChzLlRFID09IDMxLjM2KSBhbmQgKCdCUF9lcDJkX211bHRpZWNob18zMmNoX3AzX1RPTScgaW4gcy5wcm90b2NvbF9uYW1lKToKICAgICAgICAgICAgaW5mb1tmdW5jX21vdmllX2VjaG9fMl0uYXBwZW5kKHMuc2VyaWVzX2lkKQogICAgICAgIGlmIChzLmRpbTMgPT0gOTIpIGFuZCAoJ2dyZV9maWVsZF9tYXBwaW5nX0FBSCcgaW4gcy5wcm90b2NvbF9uYW1lKToKICAgICAgICAgICAgaW5mb1tmbWFwX21hZ25pdHVkZV0uYXBwZW5kKHMuc2VyaWVzX2lkKQogICAgICAgIGlmIChzLmRpbTMgPT0gNDYpIGFuZCAoJ2dyZV9maWVsZF9tYXBwaW5nX0FBSCcgaW4gcy5wcm90b2NvbF9uYW1lKToKICAgICAgICAgICAgaW5mb1tmbWFwX3BoYXNlXS5hcHBlbmQocy5zZXJpZXNfaWQpCiAgICAgICAgaWYgKHMuZGltMyA9PSA2NCkgYW5kICgnZ3JlX2ZpZWxkX21hcHBpbmdfQUFIJyBpbiBzLnByb3RvY29sX25hbWUpOgogICAgICAgICAgICBpbmZvW2ZtYXBfbWFnbml0dWRlXS5hcHBlbmQocy5zZXJpZXNfaWQpCiAgICAgICAgaWYgKHMuZGltMyA9PSAzMikgYW5kICgnZ3JlX2ZpZWxkX21hcHBpbmdfQUFIJyBpbiBzLnByb3RvY29sX25hbWUpOgogICAgICAgICAgICBpbmZvW2ZtYXBfcGhhc2VdLmFwcGVuZChzLnNlcmllc19pZCkKICAgIHJldHVybiBpbmZvCmBgYAoKVXNlIHRoZSBoZXVyaXN0aWMgZmlsZSB0byBjb252ZXJ0IHRoZSBEaWNvbSBmaWxlcyB0byAubmlpLmd6IChuaWZ0aSkgYW5kIGNyZWF0ZSAuanNvbiBmaWxlczoKYGBge2Jhc2h9CmRvY2tlciBydW4gLS1ybSAtaXQgLXYgL1ZvbHVtZXMvUHJvamVjdDAyNTUvOi9iYXNlIG5pcHkvaGV1ZGljb252OmxhdGVzdCAtZCAvYmFzZS9kYXRhc2V0XzQvc291cmNlZGF0YS9zdWIte3N1YmplY3R9LyouSU1BIC1vIC9iYXNlL2RhdGFzZXRfNCAtZiAvYmFzZS9jb2RlL2hldXJpc3RpY19hbnRocm9tLnB5IC1zIDQwMSAtYyBkY20ybmlpeCAtYiAtLW92ZXJ3cml0ZQpgYGAKCkZvciBkYXRhc2V0XzEgKGZvciBkYXRhc2V0XzEgYWRkIHNlcy17c2Vzc2lvbn0vIGFuZCAtLXNzIDAxIGFuZCAuZGNtKS4gTW92aWUgZm9yIHN1Yi0xMDEgYW5kIDEwMiBpcyBpbiBzZXMtMDI6CmBgYHtiYXNofQpkb2NrZXIgcnVuIC0tcm0gLWl0IC12IC9Wb2x1bWVzL1Byb2plY3QwMjU1LzovYmFzZSBuaXB5L2hldWRpY29udjpsYXRlc3QgLWQgL2Jhc2UvZGF0YXNldF8xL3NvdXJjZWRhdGEvc3ViLXtzdWJqZWN0fS9zZXMte3Nlc3Npb259LyouZGNtIC1vIC9iYXNlL2RhdGFzZXRfMSAtZiAvYmFzZS9jb2RlL2hldXJpc3RpY19hbnRocm9tLnB5IC1zIDEyMSAtc3MgMDIgLWMgZGNtMm5paXggLWIgLS1vdmVyd3JpdGUKYGBgCgpPbiB0aGUgZ3JpZCBkbyAoU3ViLTExNiB3YXMgZG9uZSBtYW51YWxseSBpbiBkY20ybmlpZ3VpKTogCgpUeXBlIGluIGJhc2ggYmVmb3JlIHJ1bm5pbmcKCkRhdGFzZXRfMToKYGBge2Jhc2h9CnNpbmd1bGFyaXR5IHJ1biAtQiAvYW5hbHlzZS9Qcm9qZWN0MDI1NS86L2Jhc2UgL2FuYWx5c2UvUHJvamVjdDAyNTUvbXlfaW1hZ2VzL2hldWRpY29udl9sYXRlc3Quc2lmIC1kIC9iYXNlL2RhdGFzZXRfMS9zb3VyY2VkYXRhL3N1Yi17c3ViamVjdH0vc2VzLXtzZXNzaW9ufS8qLmRjbSAtbyAvYmFzZS9kYXRhc2V0XzEvIC1mIC9iYXNlL2NvZGUvaGV1cmlzdGljX2FudGhyb20ucHkgLXMgMTE2IC1zcyAwMSAtYyBkY20ybmlpeCAtYiAtLW92ZXJ3cml0ZQpgYGAKCkRhdGFzZXRfMiAtIDQ6CmBgYHtiYXNofQpzaW5ndWxhcml0eSBydW4gLUIgL2FuYWx5c2UvUHJvamVjdDAyNTUvOi9iYXNlIC9hbmFseXNlL1Byb2plY3QwMjU1L215X2ltYWdlcy9oZXVkaWNvbnZfbGF0ZXN0LnNpZiAtZCAvYmFzZS9kYXRhc2V0XzIvc291cmNlZGF0YS9zdWIte3N1YmplY3R9LyouSU1BIC1vIC9iYXNlL2RhdGFzZXRfMi8gLWYgL2Jhc2UvY29kZS9oZXVyaXN0aWNfYW50aHJvbS5weSAtcyAyMDEgLWMgZGNtMm5paXggLWIgLS1vdmVyd3JpdGUKYGBgCgojIyAyLjMgQW5vbnltaXplIHRoZSBkYXRhIApEZWZhY2UgdXNpbmcgW1B5ZGVmYWNlXShodHRwczovL2dpdGh1Yi5jb20vcG9sZHJhY2tsYWIvcHlkZWZhY2UpOgpgYGB7YmFzaH0KIyEvYmluL2Jhc2gKCnNldCAtZSAKIyMjI0ZvciBsb29wIHRoYXQgZGVmYWNlcyB0aGUgTVJJIHBlciBzdWJqZWN0IGFuZCByZXBsYWNlcyB0aGUgb2xkIE1SSSB3aXRoIHRoZSBuZXcgZGVmYWNlZCBNUkkKcm9vdGZvbGRlcj0vVm9sdW1lcy9Qcm9qZWN0MDI1NS9kYXRhc2V0XzQKCmZvciBzdWJqIGluIDQwMTsgZG8KCWVjaG8gIkRlZmFjaW5nIHBhcnRpY2lwYW50ICRzdWJqIgpweWRlZmFjZSAke3Jvb3Rmb2xkZXJ9L3N1Yi0ke3N1Ymp9L2FuYXQvc3ViLSR7c3Vian1fVDF3Lm5paS5negpybSAtZiAke3Jvb3Rmb2xkZXJ9L3N1Yi0ke3N1Ymp9L2FuYXQvc3ViLSR7c3Vian1fVDF3Lm5paS5negptdiAke3Jvb3Rmb2xkZXJ9L3N1Yi0ke3N1Ymp9L2FuYXQvc3ViLSR7c3Vian1fVDF3X2RlZmFjZWQubmlpLmd6ICR7cm9vdGZvbGRlcn0vc3ViLSR7c3Vian0vYW5hdC9zdWItJHtzdWJqfV9UMXcubmlpLmd6IApkb25lCmBgYAoKRm9yIGRhdGFzZXRfMToKc2VzLTAxOiAxMDEgMTAyIDEwMyAxMDcgMTEyIDExMyAxMTcgMTE4IDExOSAxMjIgMTIzIDEyNCAxMjgKc2VzLTAyOiAxMDQgMTA1IDEwNiAxMDggMTA5IDExMCAxMTEgMTE1IDExNiAxMjAgMTIxIDEyNSAxMjYgMTI3CmBgYHtiYXNofQojIS9iaW4vYmFzaAoKc2V0IC1lIApyb290Zm9sZGVyPS9Wb2x1bWVzL1Byb2plY3QwMjU1L2RhdGFzZXRfMQoKZm9yIHN1YmogaW4gMTI5OyBkbwoJZWNobyAiRGVmYWNpbmcgcGFydGljaXBhbnQgJHN1YmoiCmZvciBzZXNzaW9uIGluIDAxOyBkbwpmb3IgZWNobyBpbiAxIDIgMyA0IDU7IGRvCnB5ZGVmYWNlICR7cm9vdGZvbGRlcn0vc3ViLSR7c3Vian0vc2VzLSR7c2Vzc2lvbn0vYW5hdC9zdWItJHtzdWJqfV9zZXMtJHtzZXNzaW9ufV9lY2hvLSR7ZWNob31fVDF3Lm5paS5negpybSAtZiAke3Jvb3Rmb2xkZXJ9L3N1Yi0ke3N1Ymp9L3Nlcy0ke3Nlc3Npb259L2FuYXQvc3ViLSR7c3Vian1fc2VzLSR7c2Vzc2lvbn1fZWNoby0ke2VjaG99X1Qxdy5uaWkuZ3ogCm12ICR7cm9vdGZvbGRlcn0vc3ViLSR7c3Vian0vc2VzLSR7c2Vzc2lvbn0vYW5hdC9zdWItJHtzdWJqfV9zZXMtJHtzZXNzaW9ufV9lY2hvLSR7ZWNob31fVDF3X2RlZmFjZWQubmlpLmd6ICR7cm9vdGZvbGRlcn0vc3ViLSR7c3Vian0vc2VzLSR7c2Vzc2lvbn0vYW5hdC9zdWItJHtzdWJqfV9zZXMtJHtzZXNzaW9ufV9lY2hvLSR7ZWNob31fVDF3Lm5paS5neiAKZG9uZQpkb25lCmRvbmUKYGBgCgojIyAyLjQgVXBkYXRlIHRoZSAuanNvbiBmaWxlIGZvciB0aGUgZm1hcHMgZm9yIGRhdGFzZXRfMyBhbmQgZGF0YXNldF80CllvdSBuZWVkIHRvIHNwZWNpZnkg4oCcSW50ZW5kZWRGb3LigJ0gZmllbGQgaW4gdGhlIF9waGFzZWRpZmYuanNvbiBmaWxlcyB0byBwb2ludCB3aGljaCBzY2FucyB0aGUgZXN0aW1hdGVkIGZpZWxkbWFwIHNob3VsZCBiZSBhcHBsaWVkIHRvLgoKUnVuIHRoZSBmb2xsb3dpbmcgc2NyaXB0ICh0aGFua3MgdG8gTWljaGVsZSBTdmFuZXJhIGZvciB0aGUgY29kZSk6CmBgYHtweXRob259CnB5dGhvbiBjaGFuZ2VfanNvbi5weQpgYGAKCiMjIDIuNSBDb21iaW5lIHRoZSBkdWFsLWVjaG8gcnVucyBmb3IgZGF0YXNldF80CkZvciBkYXRhc2V0XzQgd2UgbmVlZCB0byBjb21iaW5lIHRoZSB0d28gZWNobydzIChzZWUgW05ldXJvU3Rhcl0oaHR0cHM6Ly9uZXVyb3N0YXJzLm9yZy90L2ZtcmlwcmVwLWRvZXMtbm90LWNvbWJpbmUtbXVsdGktZWNoby10aW1lc2VyaWVzLzMzOTgvMikgZm9yIG1vcmUgaW5mby4gV2UgY3JlYXRlZCBhIGR1YWxfc3VtIHZvbHVtZSBieSBhZGRpbmcgdGhlIHR3byBpbWFnZXMgdG9nZXRoZXIgKHNlZSBbSGFsYWkgZXQgYWwuIDIwMTRdKGh0dHBzOi8vb25saW5lbGlicmFyeS53aWxleS5jb20vZG9pL2Z1bGwvMTAuMTAwMi9oYm0uMjI0NjMpLiAKClJ1biB0aGUgZm9sbG93aW5nIHNjcmlwdCAodGhhbmtzIHRvIFR5bGVyIE1vcmdhbiBmb3IgdGhlIGNvZGUpOgpgYGB7cHl0aG9ufQpweXRob24gc3VtX2VjaG8ucHkKYGBgCgojIyAyLjYgVGhlb3J5LW9mLU1pbmQgZXZlbnQgcHJvdG9jb2xzIApDcmVhdGUgdHN2IGZpbGUgZm9yIGZ1bmN0aW9uYWwgbG9jYWxpc2VyLiBFdmVudCBjb2RpbmcgKGluIHM7IDEwcyBvZiBmaXhhdGlvbiBiZWZvcmUgbW92aWUgc3RhcnRzOyBhY2NvdW50aW5nIGZvciBoZW1vZHluYW1pYyBsYWcpIGlzIGJhc2VkIG9uIFJpY2hhcmRzb24gZXQgYWwuIDIwMTggLSByZXZlcnNlIGNvcnJlbGF0aW9uIGFuYWx5c2VzLiAKIApOb3RlOiBGb3Igc3ViLTMyMiB0aGUgdHJpZ2dlciB3YXMgYXQgdGhlIHN0YXJ0IG9mIHRoZSBtb3ZpZSAodGh1cyBjcmVhdGUgYSBkaWZmZXJlbnQgdHN2LCB3aXRoIGV2ZW50IC0gMTBzKS4KQ2hlY2sgdGhlIHRyaWdnZXJzIGZvciBkYXRhc2V0XzEuCmBgYHtyfQpQYXJ0bHlDbG91ZHkgPC0gZGF0YS5mcmFtZShvbnNldCA9IGMoODYsIDk4LCAxMjAsIDE3NiwgMjM4LCAyNTIsIDMwMCwgNzAsIDkyLCAxMDYsIDEzNiwgMTk0LCAyMTAsIDIyOCwgMjYyLCAzMTIpLCAjY3JlYXRlIHRoZSBldmVudHMgKHNhbWUgZm9yIGV2ZXJ5IHN1YikKICAgICAgICAgICAgICAgICAgICAgICAgICAgZHVyYXRpb24gPSBjKDQsIDYsIDQsIDE2LCA2LCA4LCA2LCA0LCAyLCA0LCAxMCwgNCwgMTIsIDYsIDYsIDQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICB0cmlhbF90eXBlID0gYyhyZXAoIm1lbnRhbCIsNyksIHJlcCgicGFpbiIsOSkpKQoKI2RhdGFzZXRfMQpmb3IgKHN1YiBpbiAxMDI6MTI5KXsgI25vdGU6IGxvY2FsaXNlcnMgZm9yIHN1Yi0xMDEgYXJlIGluIHNlcy0wMgogIGZpbGVuYW1lID0gcGFzdGUoIi9Wb2x1bWVzL1Byb2plY3QwMjU1L2RhdGFzZXRfMS9zdWItIiwgc3ViLCAiL3Nlcy0wMS9mdW5jL3N1Yi0iLCBzdWIsICJfc2VzLTAxX3Rhc2stbW92aWVfZXZlbnRzLnRzdiIsIHNlcCA9IiIpCndyaXRlLnRhYmxlKFBhcnRseUNsb3VkeSwgZmlsZSA9IGZpbGVuYW1lLCBzZXA9Ilx0Iiwgcm93Lm5hbWVzID0gRkFMU0UsIHF1b3RlID0gRkFMU0UpCn0KI2RhdGFzZXRfMgpmb3IgKHN1YiBpbiAyMDE6MjM1KXsgCiAgZmlsZW5hbWUgPSBwYXN0ZSgiL1ZvbHVtZXMvUHJvamVjdDAyNTUvZGF0YXNldF8yL3N1Yi0iLCBzdWIsICIvZnVuYy9zdWItIiwgc3ViLCAiX3Rhc2stbW92aWVfZXZlbnRzLnRzdiIsIHNlcCA9IiIpCndyaXRlLnRhYmxlKFBhcnRseUNsb3VkeSwgZmlsZSA9IGZpbGVuYW1lLCBzZXA9Ilx0Iiwgcm93Lm5hbWVzID0gRkFMU0UsIHF1b3RlID0gRkFMU0UpCn0KI2RhdGFzZXRfMwpmb3IgKHN1YiBpbiAzMDE6MzIyKXsgI25vdGU6IGxvY2FsaXNlcnMgZm9yIHN1Yi0zMjIgc2hvdWxkIGhhdmUgdC0xMCAobm8gdHJpZ2dlcikgPC1tYW51YWxseSBjb3JyZWN0IHRoaXMKICBmaWxlbmFtZSA9IHBhc3RlKCIvVm9sdW1lcy9Qcm9qZWN0MDI1NS9kYXRhc2V0XzMvc3ViLSIsIHN1YiwgIi9mdW5jL3N1Yi0iLCBzdWIsICJfdGFzay1tb3ZpZV9ldmVudHMudHN2Iiwgc2VwID0iIikKd3JpdGUudGFibGUoUGFydGx5Q2xvdWR5LCBmaWxlID0gZmlsZW5hbWUsIHNlcD0iXHQiLCByb3cubmFtZXMgPSBGQUxTRSwgcXVvdGUgPSBGQUxTRSkKfQojZGF0YXNldF80CmZvciAoc3ViIGluIDQwMTo0MjIpeyAKICBmaWxlbmFtZSA9IHBhc3RlKCIvVm9sdW1lcy9Qcm9qZWN0MDI1NS9kYXRhc2V0XzQvc3ViLSIsIHN1YiwgIi9mdW5jL3N1Yi0iLCBzdWIsICJfdGFzay1tb3ZpZV9ldmVudHMudHN2Iiwgc2VwID0iIikKd3JpdGUudGFibGUoUGFydGx5Q2xvdWR5LCBmaWxlID0gZmlsZW5hbWUsIHNlcD0iXHQiLCByb3cubmFtZXMgPSBGQUxTRSwgcXVvdGUgPSBGQUxTRSkKfQpgYGAKCiMjIDIuNiBCSURTIHZhbGlkYXRpb24KVXNlIHRoZSBCSURTLVZhbGlkYXRvciB0byBjaGVjayBpZiB0aGUgZGF0YXNldCBpcyBCSURTIGNvbXBsaWFudDoKYGBge2Jhc2h9CmRvY2tlciBydW4gLXRpIC0tcm0gLXYgL1ZvbHVtZXMvUHJvamVjdDAyNTUvZGF0YXNldF80Oi9kYXRhOnJvIGJpZHMvdmFsaWRhdG9yIC9kYXRhCmBgYAoKIyAzLiBQcmVwcm9jZXNzaW5nIHsudGFic2V0fQoKIyMgMy4xIFJ1biBNUlFJQwpNUklRQyBpcyBhIGRvY2tlciB0b29sIHRvIGRvIHF1YWxpdHkgY29udHJvbCBvZiB0aGUgZGF0YS4gTW9yZSBpbmZvIFtoZXJlXShodHRwczovL3BvbGRyYWNrbGFiLmdpdGh1Yi5pby9tcmlxYy8pLgoKTVJJUUMgMC4xNC4yIHdhcyB1c2VkOgpgYGB7YmFzaH0KZG9ja2VyIHJ1biAtaXQgLS1ybSAtdiAvVm9sdW1lcy9Qcm9qZWN0MDI1NS9kYXRhc2V0XzEvOi9kYXRhOnJvIC12IC9Wb2x1bWVzL1Byb2plY3QwMjU1L2RhdGFzZXRfMS9kZXJpdmF0aXZlcy9tcmlxYzovb3V0IHBvbGRyYWNrbGFiL21yaXFjOjAuMTQuMiAvZGF0YSAvb3V0IHBhcnRpY2lwYW50IC0tcGFydGljaXBhbnQtbGFiZWwgMTAxIC1tIFQxdyBib2xkIC0taWNhIC0tZmZ0LXNwaWtlcy1kZXRlY3RvciAKYGBgCgpPbiB0aGUgZ3JpZCBkbyAoY2QgaW4gL2FuYWx5c2UgZm9sZGVyKToKYGBge2Jhc2h9CnNpbmd1bGFyaXR5IHJ1biAtLWNsZWFuZW52IC9hbmFseXNlL1Byb2plY3QwMjU1L215X2ltYWdlcy9tcmlxYy0wLjE0LjIuc2ltZyAvYW5hbHlzZS9Qcm9qZWN0MDI1NS9kYXRhc2V0XzEgL2FuYWx5c2UvUHJvamVjdDAyNTUvZGF0YXNldF8xL2Rlcml2YXRpdmVzL21yaXFjIHBhcnRpY2lwYW50IC0tcGFydGljaXBhbnQtbGFiZWwgMTIzIC1tIFQxdyBib2xkIC0taWNhIC0tZmZ0LXNwaWtlcy1kZXRlY3RvciAtdyAvYW5hbHlzZS9Qcm9qZWN0MDI1NS93b3JrCmBgYAoKUnVuIGl0IHNlcGVyYXRlbHkgZm9yIHRoZSBkYXRhc2V0cy4gQ2hhbmdlIHBhcnRpY2lwYW50IHRvIGdyb3VwIHRvIGNyZWF0ZSB0aGUgZ3JvdXAgcmVwb3J0czoKYGBge2Jhc2h9CmRvY2tlciBydW4gLWl0IC0tcm0gLXYgL1ZvbHVtZXMvUHJvamVjdDAyNTUvZGF0YXNldF80LzovZGF0YTpybyAtdiAvVm9sdW1lcy9Qcm9qZWN0MDI1NS9kYXRhc2V0XzQvZGVyaXZhdGl2ZXMvbXJpcWM6L291dCBwb2xkcmFja2xhYi9tcmlxYzowLjE0LjIgL2RhdGEgL291dCBncm91cApgYGAKCiMjIDMuMiBDb21wYXJlIE1SSVFDClBsb3QgdGhlIG91dHB1dC4gVGhpcyBpcyBiYXNlZCBvbiBbTVJJUUNlcHRpb25dKGh0dHBzOi8vZ2l0aHViLmNvbS9lbGl6YWJldGhiZWFyZC9tcmlxY2VwdGlvbikuIFRoZSBNUklRQ2VwdGlvbiBWaXN1YWxpemF0aW9uIGJ5IENhdGhlcmluZSBXYWxzaCB3YXMgYWRhcHRlZC4gQWRqdXN0IHRoZSBmaWx0ZXIgaWYgeW91IHdhbnQgdG8gbG9vayBhdCBkaWZmZXJlbnQgbWVhc3VyZXMuCgpBZGp1c3QgdGhpcyB0byB5b3VyIGxpa2luZyAoZS5nLiBib2xkOiBmZF9tZWFuLCBmZF9wZXJjLCBkdmFyc19zdGQsIGR2YXJzX3ZzdGQsIGdjb3IsIHRzbnIsIHQxdzogY2p2LCBjbnIsIHNuciwgZWZjLCBpbnUsIHdtMm1heCwgZndobSkgYW5kIG1vZGFsaXR5IChib2xkIG9yIHQxdyk6CmBgYHtyfQpRQ21lYXN1cmUgPC0gImZkX21lYW4iIAptb2RhbGl0eSA8LSAiYm9sZCIKYGBgCgpSdW4gdGhlIGZvbGxvd2luZyBjb2RlLiBDaGFuZ2UgdGhlIHNjcmlwdCBiZWxvdyB0byBsb2FkIHRoZSBncm91cCByZXN1bHRzIGZvciB0aGUgZGlmZmVyZW50IGRhdGFzZXRzOgpgYGB7cn0KI2xpYnJhcmllcwpsaWJyYXJ5KCJ0aWR5dmVyc2UiKQpzb3VyY2UoIi9Wb2x1bWVzL1Byb2plY3QwMjU1L2NvZGUvUl9yYWluY2xvdWRzLlIiKQoKI2xvYWQgb3duIGRhdGEKREYuZGF0YXNldDEgIDwtIHJlYWRfdHN2KGZpbGUgPSBwYXN0ZSgiL1ZvbHVtZXMvUHJvamVjdDAyNTUvZGF0YXNldF8xL2Rlcml2YXRpdmVzL21yaXFjL2dyb3VwXyIsIG1vZGFsaXR5LCAiLnRzdiIsIHNlcCA9IiIpKSAlPiUKICBnYXRoZXIoIm1lYXN1cmUiLCAidmFsdWUiLCAyOjQ2KSAlPiUKICBzZWxlY3QoImJpZHNfbmFtZSIsIm1lYXN1cmUiLCAidmFsdWUiKQoKREYuZGF0YXNldDIgPC0gcmVhZF90c3YoZmlsZSA9IHBhc3RlKCIvVm9sdW1lcy9Qcm9qZWN0MDI1NS9kYXRhc2V0XzIvZGVyaXZhdGl2ZXMvbXJpcWMvZ3JvdXBfIiwgbW9kYWxpdHksICIudHN2Iiwgc2VwID0iIikpICU+JQogIGdhdGhlcigibWVhc3VyZSIsICJ2YWx1ZSIsIDI6NDYpICU+JQogIHNlbGVjdCgiYmlkc19uYW1lIiwibWVhc3VyZSIsICJ2YWx1ZSIpCgpERi5kYXRhc2V0MyA8LSByZWFkX3RzdihmaWxlID0gcGFzdGUoIi9Wb2x1bWVzL1Byb2plY3QwMjU1L2RhdGFzZXRfMy9kZXJpdmF0aXZlcy9tcmlxYy9ncm91cF8iLCBtb2RhbGl0eSwgIi50c3YiLCBzZXAgPSIiKSkgJT4lCiAgZ2F0aGVyKCJtZWFzdXJlIiwgInZhbHVlIiwgMjo0NikgJT4lCiAgc2VsZWN0KCJiaWRzX25hbWUiLCJtZWFzdXJlIiwgInZhbHVlIikKCkRGLmRhdGFzZXQ0IDwtIHJlYWRfdHN2KGZpbGUgPSBwYXN0ZSgiL1ZvbHVtZXMvUHJvamVjdDAyNTUvZGF0YXNldF80L2Rlcml2YXRpdmVzL21yaXFjL2dyb3VwXyIsIG1vZGFsaXR5LCAiLnRzdiIsIHNlcCA9IiIpKSAlPiUKICBnYXRoZXIoIm1lYXN1cmUiLCAidmFsdWUiLCAyOjQ2KSAlPiUKICBzZWxlY3QoImJpZHNfbmFtZSIsIm1lYXN1cmUiLCAidmFsdWUiKSAKCiNzZWxlY3QgdGhlIG1vc3QgcmVsZXZhbnQgbWVhc3VyZXMKI3NlbGVjdGlvbk1lYXN1cmUgPC0gYygic25yIiwgInRzbnIiLCAiZWZjIiwgImZiZXIiLCAiZ3NyX3giLCAiZ3NyX3kiLCAiZHZhcnNfbnN0ZCIsICJkdmFyc19zdGQiLCAiZHZhcnNfdnN0ZCIsICJnY29yIiwgImZkX21lYW4iLCAiZmRfbnVtYmVyIiwgImZkX3BlcmNlbnRhZ2UiLCAic3Bpa2VzIiwgImFvciIsICJhcWkiKQoKI2NvbWJpbmUgZGF0YQpERi5mdWxsIDwtIGJpbmRfcm93cyhERi5kYXRhc2V0MSwgREYuZGF0YXNldDIsIERGLmRhdGFzZXQzLCAgREYuZGF0YXNldDQsIC5pZCA9ICJkYXRhc2V0IikgJT4lCiAgZ3JvdXBfYnkoZGF0YXNldCkgJT4lIAogIGZpbHRlcihtZWFzdXJlID09IFFDbWVhc3VyZSkgIyVpbiUgYyhzZWxlY3Rpb25NZWFzdXJlKSkgCgojY3JlYXRlIHJhaW5jbG91ZCBwbG90IChjaGVjayBvdXQgdGhlIFtnaXRodWJdKGh0dHBzOi8vZ2l0aHViLmNvbS9SYWluQ2xvdWRQbG90cy8pIG9yIFtwcmVwcmludF0oaHR0cHM6Ly93ZWxsY29tZW9wZW5yZXNlYXJjaC5vcmcvYXJ0aWNsZXMvNC02My92MSkKcCA8LSBnZ3Bsb3QoREYuZnVsbCxhZXMoeD1kYXRhc2V0LHk9dmFsdWUsZmlsbD1kYXRhc2V0KSkrCiAgZ2VvbV9mbGF0X3Zpb2xpbihwb3NpdGlvbj1wb3NpdGlvbl9udWRnZSh4ID0gLjIsIHkgPSAwKSxhZGp1c3QgPTIsIHRyaW0gPSBGQUxTRSwgYWxwaGEgPSAuNSwgY29sb3VyID0gTkEpKwogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IGRhdGFzZXQpLCBwb3NpdGlvbj1wb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAuMDUpLCBzaXplID0gLjUsIHNoYXBlID0gMjApKwogIGdlb21fYm94cGxvdChhZXMoeD1kYXRhc2V0LHk9dmFsdWUpLHBvc2l0aW9uPXBvc2l0aW9uX251ZGdlKHggPSAuMSwgeSA9IDApLG91dGxpZXIuc2hhcGUgPSBOQSwgYWxwaGEgPSAuNSwgd2lkdGggPSAuMSwgY29sb3VyID0gImJsYWNrIikrIAogICNmYWNldF93cmFwKC4gfiBkYXRhc2V0KSArCiAgdGhlbWVfY2xhc3NpYygpICsgeWxhYihRQ21lYXN1cmUpICsgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJSZWRzIikgKwogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJSZWRzIikgKyBnZ3RpdGxlKHBhc3RlKCJDb21wYXJpc29uIG9mIiwgbW9kYWxpdHksICJRQyBtZWFzdXJlIiwgUUNtZWFzdXJlLCAiYmV0d2VlbiBkYXRhc2V0cyIpKSArCiAgZmFjZXRfd3JhcCh+bWVhc3VyZSkKcApgYGAKCiMjIDMuMyBmTVJJcHJlcCAKZk1SSXByZXAgaXMgYSBkb2NrZXIgdG9vbCBmb3IgcHJlcHJvY2Vzc2luZyBvZiB0aGUgZk1SSSBkYXRhLiBNb3JlIGluZm8gW2hlcmVdKGh0dHBzOi8vZm1yaXByZXAucmVhZHRoZWRvY3MuaW8vZW4vc3RhYmxlLyMpCgpmTVJJcHJlcCB2ZXJzaW9uIDEuNS4yIHdhcyB1c2VkIG9uIGEgbG9jYWwgaU1hYy4KCklmIHlvdSBydW4gaW50byBtZW1vcnkgcHJvYmxlbXMgeW91IGNhbiB1c2UgLS1za2lwX2JpZHNfdmFsaWRhdGlvbjsgc2tpcHBlZCB0aGUgLS13cml0ZS1ncmFwaCBmbGFnIHRvIHNhdmUgc3BhY2UsIGFuZCAtLXVzZS1zeW4tc2RjIG9ubHkgZm9yIGRhdGFzZXRfMSBhbmQgZGF0YXRzZXRfMi4KCklmIHJ1biBvbiB0aGUgR1JJRCwgY2QgaW50byB0aGUgYW5hbHlzZSBmb2xkZXIgYW5kIHJ1bjoKYGBge2Jhc2h9CnNpbmd1bGFyaXR5IHJ1biAtLWNsZWFuZW52IC9hbmFseXNlL1Byb2plY3QwMjU1L215X2ltYWdlcy9mbXJpcHJlcC0xLjUuMi5zaW1nIC9hbmFseXNlL1Byb2plY3QwMjU1L2RhdGFzZXRfMS8gL2FuYWx5c2UvUHJvamVjdDAyNTUvZGF0YXNldF8xL2Rlcml2YXRpdmVzIHBhcnRpY2lwYW50IC0tcGFydGljaXBhbnQtbGFiZWwgc3ViLTEyOSAtLWZzLWxpY2Vuc2UtZmlsZSAvYW5hbHlzZS9Qcm9qZWN0MDI1NS9teV9pbWFnZXMvbGljZW5zZS50eHQgLS1za2lwX2JpZHNfdmFsaWRhdGlvbiAtLXVzZS1zeW4tc2QgLS1mcy1uby1yZWNvbmFsbCAtdyAvYW5hbHlzZS9Qcm9qZWN0MDI1NS93b3JrL2NvbXB1dGUwMApgYGAKClJlc2l6ZSBmdW5jdGlvbmFsIGZpbGVzIGZvciB0d28gcGFydGljaXBhbnRzIChzdWItMTE3IGFuZCBzdWItMTI1KSBmcm9tIGRhdGFzZXRfMSAoc3ViLXtzdWJ9X3Nlcy0wMV90YXNrLW1vdmllX3NwYWNlLU1OSTE1Mk5MaW4yMDA5Y0FzeW1fZGVzYy1wcmVwcm9jX2JvbGQubmlpKSB0byBhbGxvdyBmb3IgZ3JvdXAgY29tcGFyaXNvbiAocnVuIHRoaXMgaW4gTUFUTEFCKToKYGBge30Kdm94c2l6ID0gWzMgMyAzLjVdOyAlIG5ldyB2b3hlbCBzaXplIHttbX0KViA9IHNwbV9zZWxlY3QoWzEgSW5mXSwnaW1hZ2UnKTsKViA9IHNwbV92b2woVik7CmZvciBpPTE6bnVtZWwoVikKICAgYmIgICAgICAgID0gc3BtX2dldF9iYm94KFYoaSkpOwogICBWVigxOjIpICAgPSBWKGkpOwogICBWVigxKS5tYXQgPSBzcG1fbWF0cml4KFtiYigxLDopIDAgMCAwIHZveHNpel0pKnNwbV9tYXRyaXgoWy0xIC0xIC0xXSk7CiAgIFZWKDEpLmRpbSA9IGNlaWwoVlYoMSkubWF0IFwgW2JiKDIsOikgMV0nIC0gMC4xKSc7CiAgIFZWKDEpLmRpbSA9IFZWKDEpLmRpbSgxOjMpOwogICBzcG1fcmVzbGljZShWVixzdHJ1Y3QoJ21lYW4nLGZhbHNlLCd3aGljaCcsMSwnaW50ZXJwJywwKSk7ICUgMSBmb3IgbGluZWFyCmVuZApgYGAKCiMgNC4gQW5hbHlzZXMgey50YWJzZXR9CgojIyA0LjEgRXhhbXBsZSBzY3JpcHQgZm9yIGZpcnN0LWxldmVsIGFuYWx5c2lzCkV4YW1wbGUgTUFUTEFCIHNjcmlwdCAoZGF0YXNldCAzKToKYGBge30KJT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQolICAgICBTUE0gZmlyc3QtbGV2ZWwgYW5hbHlzaXMgZm9yIGZtcmlwcmVwIGRhdGEgaW4gQklEUyBmb3JtYXQKJT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQolICAgICBUaGlzIHNjcmlwdCBpcyB3cml0dGVuIGJ5IFJ1dWQgSG9ydGVuc2l1cyBhbmQgTWljaGFlbGEgS2VudAolICAgICAoVW5pdmVyc2l0eSBvZiBHbGFzZ293KS4gQmFzZWQgdXBvbiBhIHNjcmlwdCB3cml0dGVuIGJ5IAolICAgICBTaGVuZ2RvbmcgQ2hlbiAoQUNSTEFCKSBhbmQgU3RlcGhhbiBIZXVuaXMgKFRVIEVpbmRob3ZlbikuCiUKJSAgICAgQWRkZWQ6IGxvb3AgZm9yIHJ1bnMKJSAgICAgUGFyYW1ldGVycyBhcyBzcGVjaWZpZWQgYnkgU2F4ZWxhYjogaHR0cHM6Ly9zYXhlbGFiLm1pdC5lZHUvdGhlb3J5LW1pbmQtYW5kLXBhaW4tbWF0cml4LWxvY2FsaXplci1tb3ZpZS12aWV3aW5nLWV4cGVyaW1lbnQKJQolICAgICBMYXN0IHVwZGF0ZWQ6IEphbnVhcnkgMjAyMAolPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgpjbGVhciBhbGwgCgolJSBJbnB1dGRpcnMKQklEUyA9IHNwbV9CSURTKCcvVm9sdW1lcy9Qcm9qZWN0MDI1NS9kYXRhc2V0XzMvJyk7ICUgUGFyc2UgQklEUyBkaXJlY3RvcnkgKGVhc2llciB0byBxdWVyeSBpbmZvIGZyb20gZGF0YXNldCkKQklEU3ByZXByb2M9ZnVsbGZpbGUoQklEUy5kaXIsJ2Rlcml2YXRpdmVzL2ZtcmlwcmVwJyk7ICUgZ2V0IHRoZSBwcmVwcm9jZXNzZWQgZGlyZWN0b3J5Cgolc3VibGlzdCA9IHNwbV9CSURTKEJJRFMsJ3N1YmplY3RzJykgJW51bWJlciBvZiBzdWJqZWN0cwpzdWJsaXN0ID0gdHJhbnNwb3NlKEJJRFMucGFydGljaXBhbnRzLnBhcnRpY2lwYW50X2lkKSAlZ2V0IHN1YmplY3QgbGlzdCBpbmNsdWRpbmcgdGhlICdzdWInCnN1YmV4ID0gW10gCnN1Ymxpc3Qoc3ViZXgpID0gW107ICV1cGRhdGUgdGhlIHN1YmplY3RzCgp0YXNraWQ9J21vdmllJzsgJXNwZWNpZnkgdGhlIHRhc2sgdG8gYmUgYW5hbHlzZWQKCm51bVNjYW5zPTE3NTsgICVUaGUgbnVtYmVyIG9mIHZvbHVtZXMgcGVyIHJ1biA8LS0tCgpUUiA9IDI7ICAgICAlIFJlcGV0aXRpb24gdGltZSwgaW4gc2Vjb25kcyA8LS0tCnVuaXQ9J3NlY3MnOyAlIG9uc2V0IHRpbWVzIGluIHNlY3MgKHNlY29uZHMpIG9yIHNjYW5zIChUUnMpCgolJSBPdXRwdXRkaXJzCm91dHB1dGRpcj1mdWxsZmlsZShCSURTLmRpciwnZGVyaXZhdGl2ZXMvYmlkc19zcG0vZmlyc3RfbGV2ZWwnKTsgICUgcm9vdCBvdXRwdXRkaXIgZm9yIHN1Ymxpc3QKc3BtX21rZGlyKG91dHB1dGRpcixjaGFyKHN1Ymxpc3QpLCBjaGFyKHRhc2tpZCkpOyAlIGNyZWF0ZSBvdXRwdXQgZGlyZWN0b3J5CgolJSBMb29wIGZvciBzdWJsaXN0CnNwbSgnRGVmYXVsdHMnLCdmTVJJJyk7ICVJbml0aWFsaXNlIFNQTSBmbXJpCnNwbV9qb2JtYW4oJ2luaXRjZmcnKTsgICVJbml0aWFsaXNlIFNQTSBiYXRjaCBtb2RlCgpmb3IgaT0xOmxlbmd0aChzdWJsaXN0KQogICAgCiAgICAKICAgICUlIE91dHB1dCBkaXJzIHdoZXJlIHlvdSBzYXZlIFNQTS5tYXQKICAgIHN1YmRpcj1mdWxsZmlsZShvdXRwdXRkaXIsc3VibGlzdHtpfSx0YXNraWQpOwogICAgCiAgICAlJSBCYXNpYyBwYXJhbWV0ZXJzCiAgICBtYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZm1yaV9zcGVjLmRpciA9IHtzdWJkaXJ9OwogICAgbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZtcmlfc3BlYy50aW1pbmcudW5pdHMgPSB1bml0OyAlIHNwZWNpZmllZCBhYm92ZQogICAgbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZtcmlfc3BlYy50aW1pbmcuUlQgPSBUUjsgJSBzcGVjaWZpZWQgYWJvdmUKICAgIG1hdGxhYmJhdGNoezF9LnNwbS5zdGF0cy5mbXJpX3NwZWMudGltaW5nLmZtcmlfdCA9IDY4OyAlPC0tLSBsb29rIGludG8gdGhpcwogICAgbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZtcmlfc3BlYy50aW1pbmcuZm1yaV90MCA9IDM0OyAlPC0tLSBsb29rIGludG8gdGhpcwogICAgCiAgICAlJSBMb2FkIGlucHV0IGZpbGVzIGZvciB0YXNrIHNwZWNpbGl6ZWQKICAgIHN1Yl9pbnB1dGRpcj1mdWxsZmlsZShCSURTcHJlcHJvYyxzdWJsaXN0e2l9LCdmdW5jJyk7CiAgICBzdWJfaW5wdXRkaXJBPWZ1bGxmaWxlKEJJRFNwcmVwcm9jLHN1Ymxpc3R7aX0sJ2FuYXQnKTsKICAgIAogICAgJS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICAgZnVuYz1bc3ViX2lucHV0ZGlyLGZpbGVzZXAsc3VibGlzdHtpfSwnX3Rhc2stJyx0YXNraWQsJ19zcGFjZS1NTkkxNTJOTGluMjAwOWNBc3ltX2Rlc2MtcHJlcHJvY19ib2xkLm5paS5neiddOwogICAgZnVuY19uaWk9W3N1Yl9pbnB1dGRpcixmaWxlc2VwLHN1Ymxpc3R7aX0sICdfdGFzay0nLHRhc2tpZCwnX3NwYWNlLU1OSTE1Mk5MaW4yMDA5Y0FzeW1fZGVzYy1wcmVwcm9jX2JvbGQubmlpJ107CiAgICBpZiB+ZXhpc3QoZnVuY19uaWksJ2ZpbGUnKSwgZ3VuemlwKGZ1bmMpCiAgICBlbmQKICAgIHJ1bl9zY2FucyA9IHNwbV9zZWxlY3QoJ0V4cGFuZCcsZnVuY19uaWkpOwogICAgCiAgICBtYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZm1yaV9zcGVjLnNlc3MoMSkuc2NhbnMgPSBjZWxsc3RyKHJ1bl9zY2Fucyk7CiAgICAKICAgICUgTG9hZCB0aGUgY29uZGl0aW9uIGZpbGVzCiAgICBldmVudHMgPSBzcG1fbG9hZChbQklEUy5kaXIsZmlsZXNlcCxzdWJsaXN0e2l9LCcvZnVuYy8nLCBzdWJsaXN0e2l9LCdfdGFzay0nLHRhc2tpZCwnX2V2ZW50cy50c3YnXSkgJWxvYWQgVFNWIGNvbmRpdGlvbiBmaWxlCiAgICAKICAgIG5hbWVzezF9ID0gJ21lbnRhbCc7CiAgICB0ID0gc3RyY21wKG5hbWVzezF9LCBldmVudHMudHJpYWxfdHlwZSkKICAgIG9uc2V0c3sxfSA9IHRyYW5zcG9zZShldmVudHMub25zZXQodCkpOwogICAgZHVyYXRpb25zezF9ID0gdHJhbnNwb3NlKGV2ZW50cy5kdXJhdGlvbih0KSk7CiAgICAKICAgIG5hbWVzezJ9ID0gJ3BhaW4nOwogICAgdCA9IHN0cmNtcChuYW1lc3syfSwgZXZlbnRzLnRyaWFsX3R5cGUpCiAgICBvbnNldHN7Mn0gPSB0cmFuc3Bvc2UoZXZlbnRzLm9uc2V0KHQpKTsKICAgIGR1cmF0aW9uc3syfSA9IHRyYW5zcG9zZShldmVudHMuZHVyYXRpb24odCkpOwogICAgCiAgICAKICAgIGZpbGVfbWF0ID0gW3N1YmRpcixmaWxlc2VwLHN1Ymxpc3R7aX0sJ190YXNrLScsdGFza2lkLCdfY29uZGl0aW9ucy5tYXQnXTsKICAgIHNhdmUoZmlsZV9tYXQsICduYW1lcycsICdvbnNldHMnLCAnZHVyYXRpb25zJykKICAgIG1hdGxhYmJhdGNoezF9LnNwbS5zdGF0cy5mbXJpX3NwZWMuc2VzcygxKS5jb25kID0gc3RydWN0KCduYW1lJywge30sICdvbnNldCcsIHt9LCAnZHVyYXRpb24nLCB7fSwgJ3Rtb2QnLCB7fSwgJ3Btb2QnLCB7fSwgJ29ydGgnLCB7fSk7CiAgICBtYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZm1yaV9zcGVjLnNlc3MoMSkubXVsdGkgPSB7ZmlsZV9tYXR9OwogICAgCiAgICAlIENvbmZvdW5kcyBmaWxlCiAgICBjb25mb3VuZHM9c3BtX2xvYWQoW3N1Yl9pbnB1dGRpcixmaWxlc2VwLHN1Ymxpc3R7aX0sJ190YXNrLScsdGFza2lkLCdfZGVzYy1jb25mb3VuZHNfcmVncmVzc29ycy50c3YnXSkgIDsKICAgIGNvbmZvdW5kc19tYXRyaXg9W2NvbmZvdW5kcy5mcmFtZXdpc2VfZGlzcGxhY2VtZW50LCBjb25mb3VuZHMuYV9jb21wX2Nvcl8wMCxjb25mb3VuZHMuYV9jb21wX2Nvcl8wMSxjb25mb3VuZHMuYV9jb21wX2Nvcl8wMixjb25mb3VuZHMuYV9jb21wX2Nvcl8wMywgY29uZm91bmRzLmFfY29tcF9jb3JfMDQsY29uZm91bmRzLmFfY29tcF9jb3JfMDUsIGNvbmZvdW5kcy50cmFuc194LCBjb25mb3VuZHMudHJhbnNfeSwgY29uZm91bmRzLnRyYW5zX3osIGNvbmZvdW5kcy5yb3RfeCwgY29uZm91bmRzLnJvdF95LCBjb25mb3VuZHMucm90X3pdOwogICAgY29uZm91bmRzX25hbWU9W3N1YmRpcixmaWxlc2VwLHN1Ymxpc3R7aX0sJ190YXNrLScsdGFza2lkLCdfYWNvbWNvcnIudHh0J107CiAgICAKICAgIGNvbmZvdW5kc19tYXRyaXgoaXNuYW4oY29uZm91bmRzX21hdHJpeCkpID0gMCAlIG5hbm1lYW4oY29uZm91bmRzX21hdHJpeCk7ICVjaGVjayB0aGlzIDwtLS0tLQogICAgCiAgICBpZiB+ZXhpc3QoY29uZm91bmRzX25hbWUsJ2ZpbGUnKSwgZGxtd3JpdGUoY29uZm91bmRzX25hbWUsY29uZm91bmRzX21hdHJpeCkKICAgIGVuZAogICAgbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZtcmlfc3BlYy5zZXNzKDEpLm11bHRpX3JlZyA9IHtjb25mb3VuZHNfbmFtZX07CiAgICBtYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZm1yaV9zcGVjLnNlc3MoMSkuaHBmID0gMTI4OyAlIEhpZ2gtcGFzcyBmaWx0ZXIgKGhwZikgd2l0aG91dCB1c2luZyBjb25zaW5lCiAgICAKICAgICUlIE1vZGVsICAoRGVmYXVsdCkKICAgIG1hdGxhYmJhdGNoezF9LnNwbS5zdGF0cy5mbXJpX3NwZWMuZmFjdCA9IHN0cnVjdCgnbmFtZScsIHt9LCAnbGV2ZWxzJywge30pOwogICAgbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZtcmlfc3BlYy5iYXNlcy5ocmYuZGVyaXZzID0gWzAgMF07CiAgICBtYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZm1yaV9zcGVjLnZvbHQgPSAxOwogICAgbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZtcmlfc3BlYy5nbG9iYWwgPSAnU2NhbGluZyc7CiAgICBtYXNrPVtzdWJfaW5wdXRkaXJBLGZpbGVzZXAsc3VibGlzdHtpfSwnX3NwYWNlLU1OSTE1Mk5MaW4yMDA5Y0FzeW1fbGFiZWwtR01fcHJvYnNlZy5uaWkuZ3onXTsKICAgIG1hc2tfbmlpPVtzdWJfaW5wdXRkaXJBLGZpbGVzZXAsc3VibGlzdHtpfSwnX3NwYWNlLU1OSTE1Mk5MaW4yMDA5Y0FzeW1fbGFiZWwtR01fcHJvYnNlZy5uaWknXTsKICAgIAogICAgaWYgfmV4aXN0KG1hc2tfbmlpLCdmaWxlJyksIGd1bnppcChtYXNrKQogICAgZW5kCiAgICBtYXNrX25paT1bbWFza19uaWksICcsMSddCiAgICBtYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZm1yaV9zcGVjLm1hc2sgPSB7bWFza19uaWl9OwogICAgbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZtcmlfc3BlYy5tdGhyZXNoID0gMC44OwogICAgbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZtcmlfc3BlYy5jdmkgPSAnbm9uZSc7CiAgICAKICAgICUlIE1vZGVsIGVzdGltYXRpb24gKERlZmF1bHQpc3ViZGlyCiAgICBtYXRsYWJiYXRjaHsyfS5zcG0uc3RhdHMuZm1yaV9lc3Quc3BtbWF0ID0ge1tzdWJkaXIgZmlsZXNlcCAnU1BNLm1hdCddfTsKICAgIG1hdGxhYmJhdGNoezJ9LnNwbS5zdGF0cy5mbXJpX2VzdC53cml0ZV9yZXNpZHVhbHMgPSAwOwogICAgbWF0bGFiYmF0Y2h7Mn0uc3BtLnN0YXRzLmZtcmlfZXN0Lm1ldGhvZC5DbGFzc2ljYWwgPSAxOwogICAgCiAgICAlJSBDb250cmFzdHMKICAgIG1hdGxhYmJhdGNoezN9LnNwbS5zdGF0cy5jb24uc3BtbWF0ID0ge1tzdWJkaXIgZmlsZXNlcCAnU1BNLm1hdCddfTsKICAgICUgU2V0IGNvbnRyYXN0cyBvZiBpbnRlcmVzdC4KICAgIG1hdGxhYmJhdGNoezN9LnNwbS5zdGF0cy5jb24uY29uc2Vzc3sxfS50Y29uLm5hbWUgPSAnbWVudGFsX3BhaW4nOwogICAgbWF0bGFiYmF0Y2h7M30uc3BtLnN0YXRzLmNvbi5jb25zZXNzezF9LnRjb24uY29udmVjID0gWzEgLTEgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMF07CiAgICBtYXRsYWJiYXRjaHszfS5zcG0uc3RhdHMuY29uLmNvbnNlc3N7Mn0udGNvbi5uYW1lID0gJ3BhaW5fbWVudGFsJzsKICAgIG1hdGxhYmJhdGNoezN9LnNwbS5zdGF0cy5jb24uY29uc2Vzc3syfS50Y29uLmNvbnZlYyA9IFstMSAxIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDBdOwogICAgbWF0bGFiYmF0Y2h7M30uc3BtLnN0YXRzLmNvbi5kZWxldGUgPSAwOwogICAgCiAgICAlJSBSdW4gbWF0bGFiYmF0Y2ggam9icwogICAgc3BtX2pvYm1hbigncnVuJyxtYXRsYWJiYXRjaCk7CiAgICAKZW5kCmBgYAoKIyMgNC4yIEZpcnN0LWxldmVsIGFuYWx5c2lzIApSdW4gdGhlIGZvbGxvd2luIGNvbW1hbmRzIGluIHRoZSB0ZXJtaW5hbC4KCkRhdGFzZXRfMToKYGBge2Jhc2h9CmNkICIvVm9sdW1lcy9Qcm9qZWN0MDI1NS9jb2RlLyIKbWF0bGFiIC1iYXRjaCAiQklEU19TUE1fZmlyc3RsZXZlbF90b21fZGF0YXNldDEiCm1hdGxhYiAtYmF0Y2ggIkJJRFNfU1BNX2ZpcnN0bGV2ZWxfdG9tX2RhdGFzZXQxX3BwbjEwMSIKbWF0bGFiIC1iYXRjaCAiQklEU19TUE1fZmlyc3RsZXZlbF90b21fZGF0YXNldDFfcHBuMTE0IgpgYGAKCkRhdGFzZXRfMjoKYGBge2Jhc2h9CmNkICIvVm9sdW1lcy9Qcm9qZWN0MDI1NS9jb2RlLyIKbWF0bGFiIC1iYXRjaCAiQklEU19TUE1fZmlyc3RsZXZlbF90b21fZGF0YXNldDJfcHBuMjAxXzIwMiIKYGBgCgpEYXRhc2V0XzM6CmBgYHtiYXNofQpjZCAiL1ZvbHVtZXMvUHJvamVjdDAyNTUvY29kZS8iCm1hdGxhYiAtYmF0Y2ggIkJJRFNfU1BNX2ZpcnN0bGV2ZWxfdG9tX2RhdGFzZXQzIgpgYGAKCkRhdGFzZXRfNDoKYGBge2Jhc2h9CmNkICIvVm9sdW1lcy9Qcm9qZWN0MDI1NS9jb2RlLyIKbWF0bGFiIC1iYXRjaCAiQklEU19TUE1fZmlyc3RsZXZlbF90b21fZGF0YXNldDQiCmBgYAoKIyMgNC4zIENyZWF0ZSBncm91cCBtYXNrCkNyZWF0ZSBhIGdyb3VwIGF2ZXJhZ2UgZm9yIHRoZSBHTV9wcm9ic2VnLm5paSBmb3IgZWFjaCBkYXRhc2V0IGluIE1hdGxhYiAoY2hhbmdlIHRoZSBjb2RlIHBlciBkYXRhc2V0OyBydW4gdGhpcyBpbiBNQVRMQUIpOgpgYGB7fQpjbGVhciBhbGwKCnNwbSgnRGVmYXVsdHMnLCdmTVJJJyk7CnNwbV9qb2JtYW4oJ2luaXRjZmcnKTsgIAoKQklEUyA9IHNwbV9CSURTKCcvVm9sdW1lcy9Qcm9qZWN0MDI1NS9kYXRhc2V0XzMnKTsgJWNoYW5nZSB0aGlzCkJJRFNmaXJzdD1mdWxsZmlsZShCSURTLmRpciwnZGVyaXZhdGl2ZXMvZm1yaXByZXAnKTsgCgpzdWJsaXN0ID0gdHJhbnNwb3NlKEJJRFMucGFydGljaXBhbnRzLnBhcnRpY2lwYW50X2lkKSAKc3ViZXggPSBbXSAlc3ViamVjdHMgdGhhdCBkb24ndCBoYXZlIGFuIGFuYXRvbWljYWwgKDE0IGRhdGFzZXRfMSkKc3VibGlzdChzdWJleCkgPSBbXTsgCgpmb3IgaT0xOmxlbmd0aChzdWJsaXN0KQogICAgc3ViZGlyPWZ1bGxmaWxlKEJJRFNmaXJzdCxzdWJsaXN0e2l9LCAnYW5hdCcpCiAgICBtYXRsYWJiYXRjaHsxfS5zcG0udXRpbC5pbWNhbGMuaW5wdXR7aSwxfSA9IFtzdWJkaXIsIGZpbGVzZXAsIHN1Ymxpc3R7aX0sICdfc3BhY2UtTU5JMTUyTkxpbjIwMDljQXN5bV9sYWJlbC1HTV9wcm9ic2VnLm5paSwxJ10KZW5kCm1hdGxhYmJhdGNoezF9LnNwbS51dGlsLmltY2FsYy5vdXRwdXQgPSAnZGF0YXNldDNfYXZlcmFnZUdNJzsKbWF0bGFiYmF0Y2h7MX0uc3BtLnV0aWwuaW1jYWxjLm91dGRpciA9IHsnL1ZvbHVtZXMvUHJvamVjdDAyNTUvZGF0YXNldF8zL2Rlcml2YXRpdmVzL2ZtcmlwcmVwJ307ICVjaGFuZ2UgdGhpcwptYXRsYWJiYXRjaHsxfS5zcG0udXRpbC5pbWNhbGMuZXhwcmVzc2lvbiA9ICdtZWFuKFgpJzsKbWF0bGFiYmF0Y2h7MX0uc3BtLnV0aWwuaW1jYWxjLnZhciA9IHN0cnVjdCgnbmFtZScsIHt9LCAndmFsdWUnLCB7fSk7Cm1hdGxhYmJhdGNoezF9LnNwbS51dGlsLmltY2FsYy5vcHRpb25zLmRtdHggPSAxOwptYXRsYWJiYXRjaHsxfS5zcG0udXRpbC5pbWNhbGMub3B0aW9ucy5tYXNrID0gMDsKbWF0bGFiYmF0Y2h7MX0uc3BtLnV0aWwuaW1jYWxjLm9wdGlvbnMuaW50ZXJwID0gMTsKbWF0bGFiYmF0Y2h7MX0uc3BtLnV0aWwuaW1jYWxjLm9wdGlvbnMuZHR5cGUgPSA0OwoKc3BtX2pvYm1hbigncnVuJyxtYXRsYWJiYXRjaCk7CmBgYAoKIyMgNC40IEV4YW1wbGUgc2NyaXB0IGZvciBzZWNvbmQtbGV2ZWwgd2hvbGUtYnJhaW4gYW5hbHlzaXMKRXhhbXBsZSBNQVRMQUIgc2NyaXB0IChkYXRhc2V0IDMpOgpgYGB7fQolPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiUgICAgIFNQTSBzZWNvbmQtbGV2ZWwgYW5hbHlzaXMgZm9yIGZtcmlwcmVwIGRhdGEgaW4gQklEUyBmb3JtYXQKJT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQolICAgICBUaGlzIHNjcmlwdCBpcyB3cml0dGVuIGJ5IFJ1dWQgSG9ydGVuc2l1cyBhbmQgTWljaGFlbGEgS2VudCAKJSAgICAgKFVuaXZlcnNpdHkgb2YgR2xhc2dvdykgCiUKJSAgICAgTGFzdCB1cGRhdGVkOiBKYW51YXJ5IDIwMjAKJT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKCmNsZWFyIGFsbAoKJSUgSW5wdXRkaXJzCkJJRFMgPSBzcG1fQklEUygnL1ZvbHVtZXMvUHJvamVjdDAyNTUvZGF0YXNldF8zJyk7ICUgUGFyc2UgQklEUyBkaXJlY3RvcnkgKGVhc2llciB0byBxdWVyeSBpbmZvIGZyb20gZGF0YXNldCkKQklEU2ZpcnN0PWZ1bGxmaWxlKEJJRFMuZGlyLCdkZXJpdmF0aXZlcy9iaWRzX3NwbS9maXJzdF9sZXZlbCcpOyAlIGdldCB0aGUgZmlyc3QtbGV2ZWwgZGlyZWN0b3J5CgpzdWJsaXN0ID0gdHJhbnNwb3NlKEJJRFMucGFydGljaXBhbnRzLnBhcnRpY2lwYW50X2lkKSAlZ2V0IHN1YmplY3QgbGlzdCBpbmNsdWRpbmcgdGhlICdzdWInCnN1YmV4ID0gW10gJXN1YmplY3RzIHRoYXQgZG9uJ3QgaGF2ZSBhIHNlY29uZC1zZXNzaW9uCnN1Ymxpc3Qoc3ViZXgpID0gW107ICV1cGRhdGUgdGhlIHN1YmplY3RzCgolbnNlc3Npb24gPSBzcG1fQklEUyhCSURTLCdzZXNzaW9ucycpICVob3cgbWFueSBzZXNzaW9ucz8gY2FyZWZ1bCwgc29tZXRpbWVzIGNvbGxhcHNpbmcgYWNyb3NzIHNlc3Npb25zIG5vdCB3YW50ZWQKJXNlc3Npb25pZCA9ICdzZXMtMDEnICVnZXQgc2Vzc2lvbiBpZAoKdGFza2lkPSdtb3ZpZUhDJzsgJXNwZWNpZnkgdGhlIHRhc2sgdG8gYmUgYW5hbHlzZWQKCmNvbnRyYXN0PSdjb25fMDAwMSc7ICVzcGVjaWZ5IHRoZSBjb250cmFzdCB0byBiZSBhbmFseXNlZApjb250cmFzdF9uYW1lPSdtZW50YWxfaGMnOyAlc3BlY2lmeSB0aGUgbmFtZSBvZiB0aGUgY29udHJhc3QKCnNtb290aGluZyA9IDE7ICVzb29tdGhpbmcgb2YgZmlyc3QtbGV2ZWwgY29udHJhc3RzICgxPXllcywgMD1ubykKc19rZXJuZWwgPSBbNSA1IDVdCgolJSBPdXRwdXRkaXJzCm91dHB1dGRpcj1mdWxsZmlsZShCSURTLmRpciwnZGVyaXZhdGl2ZXMvYmlkc19zcG0vc2Vjb25kX2xldmVsJywgY2hhcihjb250cmFzdF9uYW1lKSk7ICAlIHJvb3Qgb3V0cHV0ZGlyIGZvciBzdWJsaXN0CnNwbV9ta2RpcihvdXRwdXRkaXIpOyAlIGNyZWF0ZSBvdXRwdXQgZGlyZWN0b3J5IAoKc3BtKCdEZWZhdWx0cycsJ2ZNUkknKTsgJUluaXRpYWxpc2UgU1BNIGZtcmkKc3BtX2pvYm1hbignaW5pdGNmZycpOyAgJUluaXRpYWxpc2UgU1BNIGJhdGNoIG1vZGUKCgolJSBTbW9vdGhpbmcgb2YgZmlyc3QtbGV2ZWwgY29udHJhc3RzCmlmIHNtb290aGluZyA9PSAxCiAgICBmb3IgaT0xOmxlbmd0aChzdWJsaXN0KQogICAgICAgIHN1YmRpcj1mdWxsZmlsZShCSURTZmlyc3Qsc3VibGlzdHtpfSwgdGFza2lkKTsKICAgICAgICBtYXRsYWJiYXRjaHsxfS5zcG0uc3BhdGlhbC5zbW9vdGguZGF0YXtpLDF9ID0gW3N1YmRpciwgZmlsZXNlcCwgY29udHJhc3QsICcubmlpLDEnXTsKICAgICAgICBtYXRsYWJiYXRjaHsxfS5zcG0uc3BhdGlhbC5zbW9vdGguZndobSA9IHNfa2VybmVsOwogICAgICAgIG1hdGxhYmJhdGNoezF9LnNwbS5zcGF0aWFsLnNtb290aC5kdHlwZSA9IDA7CiAgICAgICAgbWF0bGFiYmF0Y2h7MX0uc3BtLnNwYXRpYWwuc21vb3RoLmltID0gMDsKICAgICAgICBtYXRsYWJiYXRjaHsxfS5zcG0uc3BhdGlhbC5zbW9vdGgucHJlZml4ID0gJ3MnOwogICAgZW5kCiAgICBzcG1fam9ibWFuKCdydW4nLG1hdGxhYmJhdGNoKTsKICAgIAogICAgY2xlYXIgbWF0bGFiYmF0Y2gKZW5kCgoKJSUgTG9hZCB0aGUgY29udHJhc3RzCm1hdGxhYmJhdGNoezF9LnNwbS5zdGF0cy5mYWN0b3JpYWxfZGVzaWduLmRpciA9IHtvdXRwdXRkaXJ9OwoKZm9yIGk9MTpsZW5ndGgoc3VibGlzdCkKICAgIHN1YmRpcj1mdWxsZmlsZShCSURTZmlyc3Qsc3VibGlzdHtpfSwgdGFza2lkKTsKICAgIGlmIHNtb290aGluZyA9PSAxCiAgICAgICAgbWF0bGFiYmF0Y2h7MSwxfS5zcG0uc3RhdHMuZmFjdG9yaWFsX2Rlc2lnbi5kZXMudDEuc2NhbnN7aSwxfSA9IFtzdWJkaXIsIGZpbGVzZXAsICdzJywgY29udHJhc3QsICcubmlpLDEnXQogICAgZWxzZQogICAgICAgIG1hdGxhYmJhdGNoezEsMX0uc3BtLnN0YXRzLmZhY3RvcmlhbF9kZXNpZ24uZGVzLnQxLnNjYW5ze2ksMX0gPSBbc3ViZGlyLCBmaWxlc2VwLCBjb250cmFzdCwgJy5uaWksMSddCiAgICBlbmQKZW5kCgptYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZmFjdG9yaWFsX2Rlc2lnbi5jb3YgPSBzdHJ1Y3QoJ2MnLCB7fSwgJ2NuYW1lJywge30sICdpQ0ZJJywge30sICdpQ0MnLCB7fSk7Cm1hdGxhYmJhdGNoezF9LnNwbS5zdGF0cy5mYWN0b3JpYWxfZGVzaWduLm11bHRpX2NvdiA9IHN0cnVjdCgnZmlsZXMnLCB7fSwgJ2lDRkknLCB7fSwgJ2lDQycsIHt9KTsKbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZhY3RvcmlhbF9kZXNpZ24ubWFza2luZy50bS50bV9ub25lID0gMTsKbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZhY3RvcmlhbF9kZXNpZ24ubWFza2luZy5pbSA9IDE7Cm1hdGxhYmJhdGNoezF9LnNwbS5zdGF0cy5mYWN0b3JpYWxfZGVzaWduLm1hc2tpbmcuZW0gPSB7Jyd9OwptYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZmFjdG9yaWFsX2Rlc2lnbi5nbG9iYWxjLmdfb21pdCA9IDE7Cm1hdGxhYmJhdGNoezF9LnNwbS5zdGF0cy5mYWN0b3JpYWxfZGVzaWduLmdsb2JhbG0uZ21zY2EuZ21zY2Ffbm8gPSAxOwptYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZmFjdG9yaWFsX2Rlc2lnbi5nbG9iYWxtLmdsb25vcm0gPSAxOwoKJSUgTW9kZWwgZXN0aW1hdGlvbiAKbWF0bGFiYmF0Y2h7Mn0uc3BtLnN0YXRzLmZtcmlfZXN0LnNwbW1hdCA9IHtbb3V0cHV0ZGlyIGZpbGVzZXAgJ1NQTS5tYXQnXX07Cm1hdGxhYmJhdGNoezJ9LnNwbS5zdGF0cy5mbXJpX2VzdC53cml0ZV9yZXNpZHVhbHMgPSAwOwptYXRsYWJiYXRjaHsyfS5zcG0uc3RhdHMuZm1yaV9lc3QubWV0aG9kLkNsYXNzaWNhbCA9IDE7CgolJSBDb250cmFzdAolLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KbWF0bGFiYmF0Y2h7M30uc3BtLnN0YXRzLmNvbi5zcG1tYXQgPSB7W291dHB1dGRpciBmaWxlc2VwICdTUE0ubWF0J119OwptYXRsYWJiYXRjaHszfS5zcG0uc3RhdHMuY29uLmNvbnNlc3N7MX0udGNvbi5uYW1lID0gY29udHJhc3RfbmFtZTsKbWF0bGFiYmF0Y2h7M30uc3BtLnN0YXRzLmNvbi5jb25zZXNzezF9LnRjb24ud2VpZ2h0cyA9IDE7Cm1hdGxhYmJhdGNoezN9LnNwbS5zdGF0cy5jb24uY29uc2Vzc3sxfS50Y29uLnNlc3NyZXAgPSAnbm9uZSc7Cm1hdGxhYmJhdGNoezN9LnNwbS5zdGF0cy5jb24uZGVsZXRlID0gMDsKCiUlIFJlc3VsdHMKJS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCm1hdGxhYmJhdGNoezR9LnNwbS5zdGF0cy5yZXN1bHRzLnNwbW1hdCA9IHtbb3V0cHV0ZGlyIGZpbGVzZXAgJ1NQTS5tYXQnXX07Cm1hdGxhYmJhdGNoezR9LnNwbS5zdGF0cy5yZXN1bHRzLmNvbnNwZWMudGl0bGVzdHIgPSAnJzsKbWF0bGFiYmF0Y2h7NH0uc3BtLnN0YXRzLnJlc3VsdHMuY29uc3BlYy5jb250cmFzdHMgPSAxOwptYXRsYWJiYXRjaHs0fS5zcG0uc3RhdHMucmVzdWx0cy5jb25zcGVjLnRocmVzaGRlc2MgPSAnbm9uZSc7Cm1hdGxhYmJhdGNoezR9LnNwbS5zdGF0cy5yZXN1bHRzLmNvbnNwZWMudGhyZXNoID0gMC4wMDE7Cm1hdGxhYmJhdGNoezR9LnNwbS5zdGF0cy5yZXN1bHRzLmNvbnNwZWMuZXh0ZW50ID0gNTsKbWF0bGFiYmF0Y2h7NH0uc3BtLnN0YXRzLnJlc3VsdHMuY29uc3BlYy5jb25qdW5jdGlvbiA9IDE7Cm1hdGxhYmJhdGNoezR9LnNwbS5zdGF0cy5yZXN1bHRzLmNvbnNwZWMubWFzay5pbWFnZS5uYW1lID0geycvVm9sdW1lcy9Qcm9qZWN0MDI1NS9kYXRhc2V0XzMvZGVyaXZhdGl2ZXMvZm1yaXByZXAvZGF0YXNldDNfYXZlcmFnZUdNLm5paSwxJ307Cm1hdGxhYmJhdGNoezR9LnNwbS5zdGF0cy5yZXN1bHRzLmNvbnNwZWMubWFzay5pbWFnZS5tdHlwZSA9IDA7Cm1hdGxhYmJhdGNoezR9LnNwbS5zdGF0cy5yZXN1bHRzLnVuaXRzID0gMTsKbWF0bGFiYmF0Y2h7NH0uc3BtLnN0YXRzLnJlc3VsdHMuZXhwb3J0ezF9LnBkZiA9IHRydWU7Cm1hdGxhYmJhdGNoezR9LnNwbS5zdGF0cy5yZXN1bHRzLmV4cG9ydHsyfS5qcGcgPSB0cnVlOwptYXRsYWJiYXRjaHs0fS5zcG0uc3RhdHMucmVzdWx0cy5leHBvcnR7M30uY3N2ID0gdHJ1ZTsKbWF0bGFiYmF0Y2h7NH0uc3BtLnN0YXRzLnJlc3VsdHMuZXhwb3J0ezR9LnRzcG0uYmFzZW5hbWUgPSBjb250cmFzdF9uYW1lOwoKJSUgUnVuIG1hdGxhYmJhdGNoIGpvYnMKc3BtX2pvYm1hbigncnVuJyxtYXRsYWJiYXRjaCk7CgpgYGAKCiMjIDQuNSBTZWNvbmQtbGV2ZWwgd2hvbGUtYnJhaW4gYW5hbHlzaXMgClJ1biBpdCBzZXBlcmF0ZWx5IGZvciB0aGUgZGF0YXNldHM6CmBgYHtiYXNofQpjZCAiL1ZvbHVtZXMvUHJvamVjdDAyNTUvY29kZS8iCm1hdGxhYiAtYmF0Y2ggIkJJRFNfU1BNX3NlY29uZGxldmVsX3RvbV9kYXRhc2V0MSIKbWF0bGFiIC1iYXRjaCAiQklEU19TUE1fc2Vjb25kbGV2ZWxfdG9tX2RhdGFzZXQyIgptYXRsYWIgLWJhdGNoICJCSURTX1NQTV9zZWNvbmRsZXZlbF90b21fZGF0YXNldDMiCm1hdGxhYiAtYmF0Y2ggIkJJRFNfU1BNX3NlY29uZGxldmVsX3RvbV9kYXRhc2V0NCIKYGBgCgojIyA0LjYgVG9NIGZST0kgYW5hbHlzaXMgIApSdW4gdGhlIGZvbGxvd2luZyAoUk9JX2V4dHJhY3QubSkgc2NyaXB0IGluIG1hdGxhYiAoY2hhbmdlIHRoZSBjb2RlIHBlciBkYXRhc2V0IGFuZCByb2kgYW5kIGNvbnRyYXN0IC0gcnVuIHRoaXMgaW4gTUFUTEFCKToKYGBge30KJT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQolICAgICBmUk9JIGFuYWx5c2lzIGZvciBmbXJpcHJlcCBkYXRhIGluIEJJRFMgZm9ybWF0CiU9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KJSAgICAgVGhpcyBzY3JpcHQgaXMgd3JpdHRlbiBieSAgTWljaGFlbGEgS2VudCBhbmQgUnV1ZCBIb3J0ZW5zaXVzCiUgICAgIChVbml2ZXJzaXR5IG9mIEdsYXNnb3cpIAolCiUgICAgIExhc3QgdXBkYXRlZDogSmFudWFyeSAyMDIwCiU9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KY2xlYXIgYWxsCiVhZGQgbWFyc2JhciB0byBwYXRoCm1hcnNiYXIoJ29uJykKCiUlIElucHV0ZGlycwpCSURTID0gc3BtX0JJRFMoJy9Wb2x1bWVzL1Byb2plY3QwMjU1L2RhdGFzZXRfNCcpOyAlIHBhcnNlIEJJRFMgZGlyZWN0b3J5IChlYXNpZXIgdG8gcXVlcnkgaW5mbyBmcm9tIGRhdGFzZXQpCkJJRFNzZWNvbmQ9ZnVsbGZpbGUoQklEUy5kaXIsJ2Rlcml2YXRpdmVzL2JpZHNfc3BtL3NlY29uZF9sZXZlbCcpOyAlIGdldCB0aGUgc2Vjb25kLWxldmVsIGRpcmVjdG9yeQoKY29udHJhc3RpZCA9ICdtZW50YWwnICVjYW4gYmUgZWl0aGVyIG1lbnRhbCAodnMuIHBhaW4pIG9yIHBhaW4gKHZzLiBtZW50YWwpCm5ldHdvcmtpZCA9ICd0b20nICVjYW4gYmUgZWl0aGVyIHRvbSAodGhlb3J5LW9mLW1pbmQpIG9yIHBhaW4gKHBhaW4gbWF0cml4KQoKJSUgT3V0cHV0ZGlycwpvdXRwdXRkaXI9ZnVsbGZpbGUoQklEUy5kaXIsJ2Rlcml2YXRpdmVzL3JvaScsIG5ldHdvcmtpZCk7ICAlIHJvb3Qgb3V0cHV0ZGlyIGZvciBzdWJsaXN0CnNwbV9ta2RpcihvdXRwdXRkaXIpOyAlIGNyZWF0ZSBvdXRwdXQgZGlyZWN0b3J5IAoKJSUgTG9hZCBkZXNpZ24gbWF0cml4CnNwbV9uYW1lID0gc3BtX2xvYWQoZnVsbGZpbGUoQklEU3NlY29uZCwgZmlsZXNlcCwgY29udHJhc3RpZCAsICdTUE0ubWF0JykpCkQgID0gbWFyZG8oc3BtX25hbWUpOwoKCiUlIExvYWQgcm9pcwpwYXJjZWxzID0gZGlyKGZ1bGxmaWxlKEJJRFMuZGlyLCdkZXJpdmF0aXZlcy9wYXJjZWxzLycsIG5ldHdvcmtpZCkpCnBhcmNlbHMgPSBzdHJ1Y3QyY2VsbChwYXJjZWxzKGFycmF5ZnVuKEAoeCkgfnN0cmNtcCh4Lm5hbWUoMSksJy4nKSxwYXJjZWxzKSkpCnBhcmNlbHMoMjo2LDopID0gW10KCmZvciBpPTE6bGVuZ3RoKHBhcmNlbHMpIAogICAgcm9pID0gZnVsbGZpbGUoQklEUy5kaXIsJ2Rlcml2YXRpdmVzL3BhcmNlbHMvJywgIG5ldHdvcmtpZCwgcGFyY2Vsc3tpfSkKICAgIFIgID0gbWFyb2kocm9pKTsKICAgICUgRmV0Y2ggZGF0YSBpbnRvIG1hcnNiYXIgZGF0YSBvYmplY3QKICAgIG1ZICA9IGdldF9tYXJzeShSLCBELCAnbWVhbicpOwogICAgcm9pX2RhdGEgPSBzdW1tYXJ5X2RhdGEobVkpOyAlIGdldCBzdW1tYXJ5IHRpbWUgY291cnNlKHMpCiAgICByb2lfbmFtZSA9IFtvdXRwdXRkaXIsZmlsZXNlcCxwYXJjZWxze2l9LCcudHN2J107CiAgICBkbG13cml0ZShyb2lfbmFtZSxyb2lfZGF0YSk7CmVuZApgYGAKCiMjIDQuNyBDdXN0b20gc3RlcHMKQWRkIHN1Yi0yMDEgYW5kIHN1Yi0yMDIgdG8gZ2V0IHRoZSBmUk9JIGRhdGEgKGRpZmZlcmVudCBwYXJhbWV0ZXJzLCBub3QgaW5jbHVkZWQgaW4gdGhlIHdob2xlLWJyYWluIGFuYWx5c2lzKToKYGBge2Jhc2h9CmNkICIvVm9sdW1lcy9Qcm9qZWN0MDI1NS9jb2RlLyIKbWF0bGFiIC1iYXRjaCAiQklEU19TUE1fc2Vjb25kbGV2ZWxfdG9tX2RhdGFzZXQyXzIwMV8yMDIiCm1hdGxhYiAtYmF0Y2ggIlJPSV9leHRyYWN0XzIwMV8yMDIiCmBgYAoKIyA1LiBJREFRIHsudGFic2V0fQoKIyMgNS4xIENhbGN1bGF0aW9uIG9mIGluZGl2aWR1YWwgc2NvcmVzOgpEYXRhc2V0IDI6IHN1Yi0yMDYtMjEyLCAyMTksIDIyMS0yMiwgMjI0LTI1LCAyMjgsIDIzMSwgMjMzLTM0IGNvbXBsZXRlZCBhIHZlcnNpb24gd2l0aCB0aGUgc2NhbGUgcmFuZ2luZyBmcm9tIDEtMTAgaW5zdGVhZCBvZiAwLTEwLiBBbmFseXNlcyBzaG91bGQgYmUgcnVuIHdpdGggYW5kIHdpdGhvdXQgdGhlc2UgcGFydGljaXBhbnRzOgpgYGB7cn0Kc3ViX2V4ID0gYygyMDY6MjEyLCAyMTksIDIyMToyMjIsIDIyNDoyMjUsIDIyOCwgMjMxLCAyMzM6MjM0KQpgYGAKCkdldCB0aGUgSURBUSBkYXRhIGZvciBhbGwgdGhlIHBhcnRpY2lwYW50czoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQoKI2xvYWQgZGF0YSAoL1ZvbHVtZXMvUHJvamVjdDAyNTUvZGF0YXNldF8xL3NvdXJjZWRhdGEvKQpERi5kMSAgPC0gcmVhZF9jc3YoZmlsZSA9IHBhc3RlKCJJREFRX2RhdGFzZXQxLmNzdiIsIHNlcCA9IiIpKSAlPiUKICBnYXRoZXIoInN1YiIsICJ2YWx1ZSIsIDQ6MzIpCgpERi5kMiAgPC0gcmVhZF9jc3YoZmlsZSA9IHBhc3RlKCJJREFRX2RhdGFzZXQyLmNzdiIsIHNlcCA9IiIpKSAlPiUKICBnYXRoZXIoInN1YiIsICJ2YWx1ZSIsIDQ6MzgpIAoKREYuZDMgIDwtIHJlYWRfY3N2KGZpbGUgPSBwYXN0ZSgiSURBUV9kYXRhc2V0My5jc3YiLCBzZXAgPSIiKSkgJT4lCiAgZ2F0aGVyKCJzdWIiLCAidmFsdWUiLCA0OjI1KSAKCkRGLmQ0ICA8LSByZWFkX2NzdihmaWxlID0gcGFzdGUoIklEQVFfZGF0YXNldDQuY3N2Iiwgc2VwID0iIikpICU+JQogIGdhdGhlcigic3ViIiwgInZhbHVlIiwgNDoyNSkgCgpERi5pZGFxIDwtIGJpbmRfcm93cyhERi5kMSwgREYuZDIsIERGLmQzLCBERi5kNCwgLmlkID0gImRhdGFzZXQiKSAlPiUKICBtdXRhdGUoc3ViPWdzdWIoJ3N1Yi0nLCcnLHN1YikpJT4lCiAgdHJhbnNmb3JtKHN1Yj1hcy5pbnRlZ2VyKHN1YikpICU+JQogIG11dGF0ZShzY2FsZSA9IGFzLmZhY3RvcihpZmVsc2Uoc2NhbGUgPT0gIklEQVEtTkEiLCAiSURBUU5BIiwgIklEQVEiKSkpCgpybShERi5kMSwgREYuZDIsIERGLmQzLCBERi5kNCkKYGBgCgojIyA1LjIgUmVsaWFiaWxpdHkgb2YgSURBUQpDaGVjayB0aGUgcmVsaWFiaWxpdHkgb2YgdGhlIElEQVEgc2NhbGU6CmBgYHtyfQpsaWJyYXJ5KCJwc3ljaCIpCgpERi5pZGFxICU+JSAKICBmaWx0ZXIoc2NhbGUgPT0gIklEQVEiKSAlPiUKICAjZmlsdGVyKCFzdWIgJWluJSBzdWJfZXgpICU+JSAKICBzZWxlY3QoLXNjYWxlLCAtc3Vic2NhbGUpICAlPiUKICBzcHJlYWQoaXRlbW5yLCB2YWx1ZSkgJT4lCiAgc2VsZWN0KC1zdWIsIC1kYXRhc2V0KSAlPiUKICBhbHBoYShuYS5ybSA9IFRSVUUpCgoKYGBgCgojIyA1LjMgUmVsaWFiaWxpdHkgb2YgSURBUS1OQQpDaGVjayB0aGUgcmVsaWFiaWxpdHkgb2YgdGhlIElEQVEtTkEgc2NhbGU6CmBgYHtyfQpERi5pZGFxICU+JSAKICBmaWx0ZXIoc2NhbGUgPT0gIklEQVFOQSIpICU+JQogIGZpbHRlcighc3ViICVpbiUgIHN1Yl9leCkgJT4lIAogIHNlbGVjdCgtc2NhbGUsIC1zdWJzY2FsZSkgICU+JQogIHNwcmVhZChpdGVtbnIsIHZhbHVlKSAlPiUKICBzZWxlY3QoLXN1YiwgLWRhdGFzZXQpICU+JQogIGFscGhhKG5hLnJtID0gVFJVRSkKYGBgCgojIyA1LjQgRGlmZmVyZW5jZXMgYmV0d2VlbiBkYXRhc2V0cwpUZXN0IGlmIHRoZXJlIGFyZSBkaWZmZXJlbmNlcyBpbiBJREFRIGFuZCBJREFRLU5BIHNjb3JlcyBiZXR3ZWVuIGRhdGFzZXRzLiAKCkJlZm9yZSBmaXR0aW5nIGFueSBtb2RlbCB3ZSBlc3RhYmxpc2ggd2hpY2ggbGluayBmdW5jdGlvbiB3ZSBuZWVkIHRvIHVzZS4gVGhpcyBjb2RlIGlzIHRha2VuIGZyb20gW0tldmluIFN0YWRsZXIncyBnaXRodWJdKCBodHRwczovL2tldmluc3RhZGxlci5naXRodWIuaW8vYmxvZy9iYXllc2lhbi1vcmRpbmFsLXJlZ3Jlc3Npb24td2l0aC1yYW5kb20tZWZmZWN0cy11c2luZy1icm1zLykuIEluIHNob3J0LCBpdCB1c2VzIHRoZSBvcmRpbmFsIHBhY2thZ2UgdG8gKHF1aWNrbHkpIGZpbmQgdGhlIGxpbmsgZnVuY3Rpb24gdGhhdCBmaXRzIHRoZSBkYXRhOgpgYGB7cn0KbGlicmFyeShvcmRpbmFsKQpjdW11bGF0aXZlbW9kZWxmaXQgPC0gZnVuY3Rpb24oZm9ybXVsYSwgZGF0YSwgbGlua3M9YygibG9naXQiLCAicHJvYml0IiwgImNsb2dsb2ciLCAiY2F1Y2hpdCIpLAogICAgdGhyZXNob2xkcz1jKCJmbGV4aWJsZSIsICJlcXVpZGlzdGFudCIpLCB2ZXJib3NlPVRSVUUpIHsKICBuYW1lcyhsaW5rcykgPC0gbGlua3MKICBuYW1lcyh0aHJlc2hvbGRzKSA8LSB0aHJlc2hvbGRzCiAgbGxrcyA8LSBvdXRlcihsaW5rcywgdGhyZXNob2xkcywKICAgIFZlY3Rvcml6ZShmdW5jdGlvbihsaW5rLCB0aHJlc2hvbGQpCiAgICAgICMgY2F0Y2ggZXJyb3IgZm9yIHJlc3BvbnNlcyB3aXRoIDIgbGV2ZWxzCiAgICAgIHRyeUNhdGNoKG9yZGluYWw6OmNsbShmb3JtdWxhLCBkYXRhPWRhdGEsIGxpbms9bGluaywgdGhyZXNob2xkPXRocmVzaG9sZCkkbG9nTGlrLAogICAgICAgIGVycm9yID0gZnVuY3Rpb24oZSkgTkEpKSkKICBwcmludChsbGtzKQogIGlmICh2ZXJib3NlKSB7CiAgICBiZXN0Zml0IDwtIHdoaWNoLm1heChsbGtzKQogICAgY2F0KCJcblRoZSBiZXN0IGxpbmsgZnVuY3Rpb24gaXMgIiwgbGlua3NbYmVzdGZpdCAlJSBsZW5ndGgobGlua3MpXSwgIiB3aXRoIGEgIiwKICAgIHRocmVzaG9sZHNbMSArIGJlc3RmaXQgJS8lIGxlbmd0aCh0aHJlc2hvbGRzKV0sICIgdGhyZXNob2xkIChsb2dMaWsgIiwgbGxrc1tiZXN0Zml0XSwKICAgICIpXG4iLCBzZXA9IiIpCiAgfQogIGludmlzaWJsZShsbGtzKQp9CmBgYAoKUnVuIHRoZSBhbmFseXNlIGZvciB0aGUgYW50aHJvcG9tb3JwaGlzbSBzdWJzY2FsZToKYGBge3J9CkRGLnRlc3QgPSBERi5pZGFxICU+JSAKICBmaWx0ZXIoc2NhbGUgPT0gIklEQVEiKSAlPiUgCiAgbXV0YXRlX2FsbChhcy5mYWN0b3IpICU+JQogIG11dGF0ZSh2YWx1ZSA9IGZhY3Rvcih2YWx1ZSwgbGV2ZWxzPWMoMDoxMCksIG9yZGVyZWQ9VFJVRSkpICNhZGQgY29udHJhc3QgY29kaW5nPwpgYGAKCkdldCB0aGUgbGluayBmdW5jdGlvbjoKYGBge3J9CmN1bXVsYXRpdmVtb2RlbGZpdCh2YWx1ZSB+IDEsIGRhdGE9REYudGVzdCkKYGBgCgoxLiBGaXJzdCBjdW11bGF0aXZlIG9yZGluYWwgbW9kZWwgd2l0aCBkYXRhc2V0IGFzIGZpeGVkIGZhY3RvcjoKYGBge3J9CmxpYnJhcnkoYnJtcykKb3B0aW9ucyhtYy5jb3JlcyA9IHBhcmFsbGVsOjpkZXRlY3RDb3JlcygpKSAjcnVuIG9uY2UgKHJ1biBvbiBtdWx0aXBsZSBjb3JlcykKCm9yZC4xIDwtIGJybSgKICB2YWx1ZSB+IDEgKyBkYXRhc2V0LCAgCiAgZGF0YSAgPSBERi50ZXN0LCAgCiAgZmFtaWx5ICA9IGN1bXVsYXRpdmUoImxvZ2l0IiksCiAgZmlsZSA9ICdvcmQuMX5zaW1wbGUuUkRTJwopIApgYGAKCkdldCBzdW1tYXJ5IGFuZCBtYXJnaW5hbCBlZmZlY3RzOgpgYGB7cn0Kc3VtbWFyeShvcmQuMSkgI3Byb2IgPSAuOTkgIGZvciA5OSBjcmVkaWJsZSBpbnRlcnZhbHMKY29uZGl0aW9uYWxfZWZmZWN0cyhvcmQuMSwgImRhdGFzZXQiLCBjYXRlZ29yaWNhbCA9IFRSVUUpCnBsb3Qob3JkLjEpCmBgYAoKMi4gU2Vjb25kIGN1bXVsYXRpdmUgb3JkaW5hbCBtb2RlbCB3aXRoIGRhdGFzZXQgYXMgZml4ZWQgZmFjdG9yIGFuZCByYW5kb20gaW50ZXJjZXB0cyBmb3IgcGFydGljaXBhbnQgYW5kIGl0ZW1ucjoKYGBge3J9Cm9yZC4yIDwtIGJybSgKICB2YWx1ZSB+IDEgKyBkYXRhc2V0ICsKICAgICgxfHN1YikgKyAoMXxpdGVtbnIpLCAgIAogIGRhdGEgID0gREYudGVzdCwgIAogIGZhbWlseSAgPSBjdW11bGF0aXZlKCJsb2dpdCIpLAogIGZpbGUgPSAnb3JkLjJ+cmFuZG9tLlJEUycKKSAKYGBgCgpHZXQgc3VtbWFyeSBhbmQgbWFyZ2luYWwgZWZmZWN0czoKYGBge3J9CnN1bW1hcnkob3JkLjIpICNwcm9iID0gLjk5ICBmb3IgOTkgY3JlZGlibGUgaW50ZXJ2YWxzCmNvbmRpdGlvbmFsX2VmZmVjdHMob3JkLjIsICJkYXRhc2V0IiwgY2F0ZWdvcmljYWwgPSBUUlVFKQpwbG90KG9yZC4yKQpgYGAKCjMuIENhdGVnb3J5LXNwZWNpZmljIG1vZGVsOgpgYGB7cn0Kb3JkLjMgPC0gYnJtKAogIHZhbHVlIH4gMSArIGNzKGRhdGFzZXQpICsKICAgIChjcygxKXxzdWIpICsgKGNzKDEpfGl0ZW1uciksCiAgZGF0YSAgPSBERi50ZXN0LCAgCiAgZmFtaWx5ID0gYWNhdCgibG9naXQiKSwKICBmaWxlID0gJ29yZC4zfmNhdGVnb3J5LlJEUycKKSAgCmBgYAoKR2V0IHN1bW1hcnkgYW5kIG1hcmdpbmFsIGVmZmVjdHM6CmBgYHtyfQpzdW1tYXJ5KG9yZC4zKSAjcHJvYiA9IC45OSAgZm9yIDk5IGNyZWRpYmxlIGludGVydmFscwpjb25kaXRpb25hbF9lZmZlY3RzKG9yZC4zLCAiZGF0YXNldCIsIGNhdGVnb3JpY2FsID0gVFJVRSkKYGBgCgo0LiBBZGplY2VudC1jYXRlZ29yeSBtb2RlbCB3aXRob3V0IGNhdGVnb3J5LXNwZWNpZmljIGVmZmVjdHMgKHRvIGNoZWNrIGlmIGRpZmZlcmVuY2VzIGJldHdlZW4gbW9kZWwgMiBhbmQgMyBhcmUgbm90IGR1ZSB0byBkaWZmZXJlbnQgY2xhc3NlcyBvZiBvcmRpbmFsIG1vZGVscyk6IApgYGB7cn0Kb3JkLjQgPC0gYnJtKAogIHZhbHVlIH4gMSArIGRhdGFzZXQgKwogICAgKDF8c3ViKSArICgxfGl0ZW1uciksCiAgZGF0YSAgPSBERi50ZXN0LCAgCiAgZmFtaWx5ID0gYWNhdCgibG9naXQiKSwKICBmaWxlID0gJ29yZC40fmNhdGVnb3J5Mi5SRFMnCikgCmBgYAoKR2V0IHN1bW1hcnkgYW5kIG1hcmdpbmFsIGVmZmVjdHM6ICNzaG91bGQgYWRkIDF8aXRlbW5yIGFuZCAxfHN1YgpgYGB7cn0Kc3VtbWFyeShvcmQuNCkgI3Byb2IgPSAuOTkgIGZvciA5OSBjcmVkaWJsZSBpbnRlcnZhbHMKY29uZGl0aW9uYWxfZWZmZWN0cyhvcmQuNCwgImRhdGFzZXQiLCBjYXRlZ29yaWNhbCA9IFRSVUUpCmBgYAoKNS4gVW5lcXVhbCB2YXJpYW5jZXMgbW9kZWw6CmBgYHtyfQpvcmQuNSA8LSBicm0oCiAgZm9ybXVsYSA9IGJmKHZhbHVlIH4gMSArIGRhdGFzZXQpICsKICAgIGxmKGRpc2MgfiAwICsgZGF0YXNldCwgY21jID0gRkFMU0UpLAogIGRhdGEgPSBERi50ZXN0LAogIGZhbWlseSAgPSBjdW11bGF0aXZlKCJsb2dpdCIpLAogIGZpbGUgPSAnb3JkLjV+Y29udHJvbC5SRFMnCikgCmBgYAoKR2V0IHN1bW1hcnkgYW5kIG1hcmdpbmFsIGVmZmVjdHM6CmBgYHtyfQpzdW1tYXJ5KG9yZC41KSAjcHJvYiA9IC45OSAgZm9yIDk5IGNyZWRpYmxlIGludGVydmFscwpjb25kaXRpb25hbF9lZmZlY3RzKG9yZC41LCAiZGF0YXNldCIsIGNhdGVnb3JpY2FsID0gVFJVRSkKYGBgCgo2LiBNb2RlbCBjb21wYXJpc29uOiAKYGBge3J9CiNtb2RlbEMxIDwtIExPTyhvcmQuMSwgb3JkLjIsIG9yZC4zLCBvcmQuNCwgb3JkLjUpCiNzYXZlKG1vZGVsQzEsIGZpbGU9Im1vZGVsQzEuUkRhdGEiKQpsb2FkKCdtb2RlbEMxLlJEYXRhJykKbW9kZWxDMSAKCmBgYAoKNy4gUmVydW4gd2lubmluZyBtb2RlbCBleGNsdWRpbmcgdGhlIHBhcnRpY2lwYW50cyB0aGF0IGNvbXBsZXRlZCB0aGUgaW5jb3JyZWN0IElEQVEgdmVyc2lvbjogCmBgYHtyfQpERi50ZXN0ID0gREYudGVzdCAlPiUgCiAgZmlsdGVyKCFzdWIgJWluJSBzdWJfZXgpIAoKY3VtdWxhdGl2ZW1vZGVsZml0KHZhbHVlIH4gMSwgZGF0YT1ERi50ZXN0KQpgYGAKCjguIE1vZGVsIDIgd2hpbGUgZXhjbHVkaW5nIHRoZXNlIHBhcnRpY2lwYW50czogCmBgYHtyfQpvcmQuMkUgPC0gYnJtKAogIHZhbHVlIH4gMSArIGRhdGFzZXQgKwogICAgKDF8c3ViKSArICgxfGl0ZW1uciksICAgCiAgZGF0YSAgPSBERi50ZXN0LCAgCiAgZmFtaWx5ID0gY3VtdWxhdGl2ZShsaW5rID0gInByb2JpdCIsIHRocmVzaG9sZD0iZXF1aWRpc3RhbnQiKSwKICBmaWxlID0gJ29yZC4yRX5yYW5kb20uUkRTJwopIApgYGAKCkdldCBzdW1tYXJ5IGFuZCBtYXJnaW5hbCBlZmZlY3RzOgpgYGB7cn0Kc3VtbWFyeShvcmQuMkUpICNwcm9iID0gLjk5ICBmb3IgOTkgY3JlZGlibGUgaW50ZXJ2YWxzCmNvbmRpdGlvbmFsX2VmZmVjdHMob3JkLjJFLCAiZGF0YXNldCIsIGNhdGVnb3JpY2FsID0gVFJVRSkKYGBgCgo5LiBNb2RlbCAzIHdoaWxlIGV4Y2x1ZGluZyB0aGVzZSBwYXJ0aWNpcGFudHMgKG5vIGNvbnZlcmdlbmNlKTogCmBgYHtyfQpvcmQuM0UgPC0gYnJtKAogIHZhbHVlIH4gMSArIGNzKGRhdGFzZXQpICsKICAgIChjcygxKXxzdWIpICsgKGNzKDEpfGl0ZW1uciksCiAgZGF0YSAgPSBERi50ZXN0LCAgCiAgZmFtaWx5ID0gYWNhdChsaW5rID0gInByb2JpdCIsIHRocmVzaG9sZD0iZXF1aWRpc3RhbnQiKSwKICBmaWxlID0gJ29yZC4zRX5jYXRlZ29yeS5SRFMnCikgIAoKc3VtbWFyeShvcmQuM0UpCmBgYAoKRmluYWwgb3V0cHV0IChUYWJsZSBTNyk6CmBgYHtyfQojIGxvYWQgcmVxdWlyZWQgcGFja2FnZXMKbGlicmFyeShzalBsb3QpCmxpYnJhcnkoaW5zaWdodCkKbGlicmFyeShodHRyKQoKdGFiX21vZGVsKAogIG9yZC4yLG9yZC4yRSwKICBzaG93LnNlID0gRkFMU0UsCiAgI2NvbGxhcHNlLnNlID0gVFJVRSwKICAjcHJlZC5sYWJlbHMgPSBjKCJJbnRlcmNlcHQiLCAibGluZWFyIHByZWRpY3RvciIsICJxdWFkcmF0aWMgcHJlZGljdG9yIiksCiAgZHYubGFiZWxzID0gYygiY3VtdWxhdGl2ZSBvcmRpbmFsIG1vZGVsIiwgImN1bXVsYXRpdmUgb3JkaW5hbCBtb2RlbCAoZXhjbHVkaW5nIDE2IHBhcnRpY2lwYW50cykiKSwKICBzaG93Lm9icz1GQUxTRQopCmBgYAoKIyMgNS41IElEQVEgcGVyIHN1YmplY3QKQ2FsY3VsYXRlIHRoZSBJREFRIHBlciBzdWJqZWN0OgpgYGB7cn0KREYuaWRhcSA8LSBERi5pZGFxICU+JQogIGdyb3VwX2J5KHN1YixkYXRhc2V0LCBzY2FsZSkgJT4lCiAgc3VtbWFyaXNlKHNjb3JlID0gc3VtKHZhbHVlLCBuYS5ybSA9IFRSVUUpKSAlPiUKICB1bmdyb3VwKCklPiUKICBtdXRhdGVfYXQodmFycygtc2NvcmUpLGFzLmZhY3RvcikKYGBgCgojIyA1LjYgVmlzdWFsaXNlIHRoZSBzY29yZXMKVmlzdWFsaXNlIHRoZSBzY29yZXMgYWNyb3NzIHRoZSBkYXRhc2V0cyBhbmQgc2NhbGVzIChGaWd1cmUgUzEpOgpgYGB7cn0Kc291cmNlKCJSX3JhaW5jbG91ZHMuUiIpICMvVm9sdW1lcy9Qcm9qZWN0MDI1NS9jb2RlCnNvdXJjZSgic3VtbWFyeVNFLlIiKQp0aGVtZV9zZXQodGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxNSkpIAoKaWRhcV9zdW0gPC0gc3VtbWFyeVNFd2l0aGluKERGLmlkYXEsIG1lYXN1cmV2YXI9InNjb3JlIiwgYmV0d2VlbnZhcnM9ImRhdGFzZXQiLCB3aXRoaW52YXJzPSAic2NhbGUiLCBpZHZhcj0ic3ViIikKCkZTMSA8LSBERi5pZGFxICU+JQogIGdyb3VwX2J5KHN1YixkYXRhc2V0LCBzY2FsZSkgJT4lCiAgZ2dwbG90KC4sYWVzKHg9ZGF0YXNldCx5PXNjb3JlLGZpbGw9ZGF0YXNldCwgZ3JvdXAgPSBkYXRhc2V0KSkrCiAgZ2VvbV9mbGF0X3Zpb2xpbihwb3NpdGlvbj1wb3NpdGlvbl9udWRnZSh4ID0gLjIsIHkgPSAwKSxhZGp1c3QgPTIsIHRyaW0gPSBGQUxTRSwgYWxwaGEgPSAuNzUsIGNvbG91ciA9ICJCbGFjayIpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBkYXRhc2V0KSwgcG9zaXRpb249cG9zaXRpb25faml0dGVyKHdpZHRoID0gLjA1KSwgc2l6ZSA9IC41LCBzaGFwZSA9IDIxLCBjb2xvdXIgPSAiQmxhY2siKSArCiAgZ2VvbV9ib3hwbG90KGFlcyh4PWRhdGFzZXQseT1zY29yZSkscG9zaXRpb249cG9zaXRpb25fbnVkZ2UoeCA9IC4xLCB5ID0gMCksb3V0bGllci5zaGFwZSA9IE5BLCBhbHBoYSA9IC41LCB3aWR0aCA9IC4xLCBjb2xvdXIgPSAiYmxhY2siKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IGlkYXFfc3VtLCBhZXMoeCA9IGRhdGFzZXQsIHkgPSBzY29yZSksIHBvc2l0aW9uID0gcG9zaXRpb25fbnVkZ2UoLjMpLCBjb2xvdXIgPSAiQkxBQ0siKSsKICBnZW9tX2Vycm9yYmFyKGRhdGEgPSBpZGFxX3N1bSwgYWVzKHg9ZGF0YXNldCx5PXNjb3JlLCB5bWluID0gc2NvcmUtY2ksIHltYXggPSBzY29yZStjaSksIHBvc2l0aW9uPXBvc2l0aW9uX251ZGdlKHggPSAuMywgeSA9IDApLCB3aWR0aCA9IC4wNSkrCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJHcmV5cyIpICsKICBzY2FsZV9jb2xvdXJfYnJld2VyKHBhbGV0dGUgPSAiR3JleXMiKSArCiAgeWxhYihwYXN0ZSgic2NvcmUgKDAtMTUwKSIpKSArIAogIGdndGl0bGUocGFzdGUoIklEQVEgc2NvcmVzIGFjcm9zcyBkYXRhc2V0cyIpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKwogIGZhY2V0X3dyYXAofnNjYWxlKQpGUzEKZ2dzYXZlKCJTMS5USUZGIiwgcGxvdCA9IEZTMSwgd2lkdGggPSAyNC43LCBoZWlnaHQgPSAxNS4yNCwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDApCgpgYGAKClZpc3VhbGlzZSB0aGUgc2NvcmVzIGZvciBJREFRIHNjYWxlIG9ubHkgKEZpZ3VyZSAxQSk6CmBgYHtyfQppZGFxX3N1bSA8LSBzdW1tYXJ5U0V3aXRoaW4oREYuaWRhcSwgbWVhc3VyZXZhcj0ic2NvcmUiLCB3aXRoaW52YXJzPSAic2NhbGUiLCBpZHZhcj0ic3ViIikKIApGMUEgPC0gREYuaWRhcSAlPiUKICBmaWx0ZXIoc2NhbGUgPT0gIklEQVEiKSAlPiUKICBncm91cF9ieShzdWIpICU+JQogIGdncGxvdCguLGFlcyh4ID0gMSwgeT1zY29yZSwgZmlsbCA9ICJCbGFjayIpKSsKICBnZW9tX2ZsYXRfdmlvbGluKHBvc2l0aW9uPXBvc2l0aW9uX251ZGdlKHggPSAuMiwgeSA9IDApLGFkanVzdCA9MiwgdHJpbSA9IEZBTFNFLCBhbHBoYSA9IC43NSwgY29sb3VyID0gIkJsYWNrIikgKwogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IGRhdGFzZXQpLCBwb3NpdGlvbj1wb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAuMDUpLCBzaXplID0gLjUsIHNoYXBlID0gMjEsIGNvbG91ciA9ICJCbGFjayIpICsKICBnZW9tX2JveHBsb3QoYWVzKHg9MSx5PXNjb3JlKSxwb3NpdGlvbj1wb3NpdGlvbl9udWRnZSh4ID0gLjEyLCB5ID0gMCksb3V0bGllci5zaGFwZSA9IE5BLCBhbHBoYSA9IC41LCB3aWR0aCA9IC4xLCBjb2xvdXIgPSAiYmxhY2siKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IGlkYXFfc3VtICU+JSBmaWx0ZXIoc2NhbGUgPT0gIklEQVEiKSwgYWVzKHggPSAwLjk1LCB5ID0gc2NvcmUpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX251ZGdlKC4zKSwgY29sb3VyID0gIkJMQUNLIikrCiAgZ2VvbV9lcnJvcmJhcihkYXRhID0gaWRhcV9zdW0gJT4lIGZpbHRlcihzY2FsZSA9PSAiSURBUSIpLCBhZXMoeD0wLjk1LHk9c2NvcmUsIHltaW4gPSBzY29yZS1jaSwgeW1heCA9IHNjb3JlK2NpKSwgcG9zaXRpb249cG9zaXRpb25fbnVkZ2UoeCA9IC4zLCB5ID0gMCksIHdpZHRoID0gLjA1KSsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkdyZXlzIikgKwogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJHcmV5cyIpICsKICAjdGhlbWVfY2xhc3NpYygpICsgCiAgY29vcmRfZml4ZWQocmF0aW8gPSAxLzkwKSArIAogIHlsYWIocGFzdGUoIkRpc3Bvc2l0aW9uYWwgYW50aHJvcG9tb3JwaGlzbSAoMC0xNTApIikpICsgCiAgI2dndGl0bGUocGFzdGUoIkRpc3Bvc2l0aW9uYWwgYW50aHJvcG9tb3JwaGlzbSIpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKwogIHRoZW1lKAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCkKICAgICAgCiAgKQpGMUEKZ2dzYXZlKCJGMUEuVElGRiIsIHBsb3QgPSBGMUEsIHdpZHRoID0gMjQuNywgaGVpZ2h0ID0gMTUuMjQsIHVuaXRzID0gImNtIiwgZHBpID0gMzAwKQpgYGAKCiMjIDUuNyBNZWRpYW4gYW5kIGludGVycXVhcnRpbGUgcmFuZ2UgcGVyIGRhdGFzZXQKQ2FsY3VsYXRlIHRoZSBtZWRpYW4gSVFSIHBlciBkYXRhc2V0ICh0YWJsZSBTMik6CmBgYHtyfQpERi5pZGFxICU+JQogICNmaWx0ZXIoIXN1YiAlaW4lICBzdWJfZXgpICU+JSAKICBncm91cF9ieShzdWIsZGF0YXNldCwgc2NhbGUpICU+JQogIHN1bW1hcmlzZShzY29yZSA9IHN1bShzY29yZSkpICU+JQogIGdyb3VwX2J5KHNjYWxlKSAlPiUKICBzdW1tYXJpc2UobWVkaWFuID0gbWVkaWFuKHNjb3JlKSwKICAgICAgICAgICAgaXFyID0gSVFSKHNjb3JlKSkKYGBgCgojIDYuIGZST0kgcmVzdWx0cyB7LnRhYnNldH0KCiMjIDYuMSBEYXRhIHdyYW5nbGluZwpDcmVhdGUgZnVuY3Rpb24gdG8gbG9hZCB0aGUgZGF0YSBmb3IgdGhlIGRpZmZlcmVudCBuZXR3b3JrczoKYGBge3J9CmxpYnJhcnkoZnMpCmxpYnJhcnkodGlkeXZlcnNlKQpyb2lfZXh0cmFjdCA8LSBmdW5jdGlvbihkYXRhc2V0bm8sIHN1YnN0YXJ0LCBzdWJlbmQsIG5ldHdvcmssIG5yb2kpIHsKICAKICBkaXJfbHMocGFzdGUoImRhdGFzZXRfIiwgZGF0YXNldG5vLCAiL2Rlcml2YXRpdmVzL3JvaS8iLCBuZXR3b3JrLCBzZXAgPSAiIiksIHJlZ2V4cCA9ICJcXC50c3YkIikgJT4lIAogICAgbWFwX2RmcihyZWFkLmRlbGltLCBzZXAgPSAiXHQiLCAuaWQgPSAiaWQiLCBoZWFkZXIgPSBGQUxTRSkgICU+JQogICAgbXV0YXRlKGRhdGFzZXQgPSBkYXRhc2V0bm8pICU+JQogICAgbXV0YXRlKG5ldHdvcmsgPSBuZXR3b3JrKSAlPiUKICAgIG11dGF0ZShuZXR3b3JrID0gc3RyX2V4dHJhY3QobmV0d29yaywgInRvbXxwYWluIikpICU+JQogICAgbXV0YXRlKGlkID0gc3RyX2V4dHJhY3QoaWQsICJkbXBmY3xtbXBmY3x2bXBmY3xsdHBqfHJ0cGp8cHJlY3xhbWNjfGxtZmd8cm1mZ3xsczJ8cnMyfGxpbnN1bGF8cmluc3VsYSIpKSAlPiUKICAgIHJlbmFtZShyb2kgPSBpZCwgY29udHJhc3QgPSBWMSkgJT4lCiAgICBtdXRhdGUoc3ViID0gcmVwKHN1YnN0YXJ0OnN1YmVuZCwgdGltZXM9bnJvaSwgZWFjaD0xKSkgJT4lCiAgICBzZWxlY3QoNSwzLDQsMToyKQp9IApgYGAKCkxvYWQgdGhlIGRhdGEgZm9yIHRoZSBUaGVvcnktb2YtTWluZCBuZXR3b3JrOgpgYGB7cn0KREYuZDEgPC0gcm9pX2V4dHJhY3QoMSwgMTAxLCAxMjksICJ0b20iLCA2KQpERi5kMi5hIDwtIHJvaV9leHRyYWN0KDIsIDIwMSwgMjAyLCAidG9tLzIwMV8yMDIiLCA2KQpERi5kMi5iIDwtIHJvaV9leHRyYWN0KDIsIDIwMywgMjM1LCAidG9tIiwgNikKREYuZDMgPC0gcm9pX2V4dHJhY3QoMywgMzAxLCAzMjIsICJ0b20iLCA2KQpERi5kNCA8LSByb2lfZXh0cmFjdCg0LCA0MDEsIDQyMiwgInRvbSIsIDYpCgpERi50ZW1wIDwtIGJpbmRfcm93cyhERi5kMSwgREYuZDIuYSwgREYuZDIuYiwgREYuZDMsIERGLmQ0KSAKYGBgCgpMb2FkIHRoZSBkYXRhIGZvciB0aGUgUGFpbiBNYXRyaXg6CmBgYHtyfQpERi5kMSA8LSByb2lfZXh0cmFjdCgxLCAxMDEsIDEyOSwgInBhaW4iLCA3KQpERi5kMi5hIDwtIHJvaV9leHRyYWN0KDIsIDIwMSwgMjAyLCAicGFpbi8yMDFfMjAyLyIsIDcpCkRGLmQyLmIgPC0gcm9pX2V4dHJhY3QoMiwgMjAzLCAyMzUsICJwYWluIiwgNykKREYuZDMgPC0gcm9pX2V4dHJhY3QoMywgMzAxLCAzMjIsICJwYWluIiwgNykKREYuZDQgPC0gcm9pX2V4dHJhY3QoNCwgNDAxLCA0MjIsICJwYWluIiwgNykKCkRGLnJvaSA8LSBiaW5kX3Jvd3MoREYudGVtcCwgREYuZDEsIERGLmQyLmEsIERGLmQyLmIsIERGLmQzLCBERi5kNCkKCnJtKERGLmQxLCBERi5kMi5hLCBERi5kMi5iLCBERi5kMywgREYuZDQsIERGLnRlbXApCmBgYAoKUmVvcmRlciBST0kgbmFtZXMgZm9yIHBsb3RzOgpgYGB7cn0Kb3JkZXIgPC0gYygicnRwaiIsICJsdHBqIiwgInByZWMiLCAidm1wZmMiLCJtbXBmYyIsImRtcGZjIiwgInJzMiIsICJsczIiLCAicmluc3VsYSIsICJsaW5zdWxhIiwgInJtZmciLCAibG1mZyIsICJhbWNjIikgIAoKREYucm9pIDwtIERGLnJvaSAlPiUKICBtdXRhdGVfYXQodmFycygtY29udHJhc3QpLGFzLmZhY3RvcikgJT4lCiAgZ3JvdXBfYnkoc3ViLCBkYXRhc2V0KSAlPiUKICBtdXRhdGUocm9pID0gZmN0X3JlbGV2ZWwocm9pLCBvcmRlcikpCmBgYAoKIyMgNi4yIFRoZW9yeS1vZi1NaW5kIG5ldHdvcmsgYWN0aXZhdGlvbiBhY3Jvc3MgZGF0YXNldHM6ClBsb3QgdGhlIFRvTSBhY3Rpdml0eSBhY3Jvc3MgcmVnaW9ucyBhbmQgZGF0YXNldHMgKEZpZ3VyZSBTMik6CmBgYHtyfQpzb3VyY2UoIlJfcmFpbmNsb3Vkcy5SIikgIy9Wb2x1bWVzL1Byb2plY3QwMjU1L2NvZGUKc291cmNlKCJzdW1tYXJ5U0UuUiIpCnRoZW1lX3NldCh0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDE1KSkgCgpyb2lfc3VtIDwtIHN1bW1hcnlTRXdpdGhpbihERi5yb2ksIG1lYXN1cmV2YXI9ImNvbnRyYXN0IiwgYmV0d2VlbnZhcnM9ImRhdGFzZXQiLCB3aXRoaW52YXJzPSBjKCJyb2kiLCJuZXR3b3JrIiksIGlkdmFyPSJzdWIiKQoKRlMyIDwtIERGLnJvaSAlPiUKICBmaWx0ZXIobmV0d29yayA9PSAidG9tIikgJT4lCiAgZ2dwbG90KC4sYWVzKHg9cm9pLHk9Y29udHJhc3QsZmlsbD1yb2kpKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJncmV5IiwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV9mbGF0X3Zpb2xpbihwb3NpdGlvbj1wb3NpdGlvbl9udWRnZSh4ID0gLjIsIHkgPSAwKSxhZGp1c3QgPTIsIHRyaW0gPSBGQUxTRSwgY29sb3VyID0gIkJsYWNrIikgKwogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IHJvaSwgZmlsbCA9IHJvaSksIHBvc2l0aW9uPXBvc2l0aW9uX2ppdHRlcih3aWR0aCA9IC4wNSksIHNpemUgPSAuNSwgc2hhcGUgPSAyMSwgY29sb3VyID0gIkJsYWNrIikgKwogIGdlb21fYm94cGxvdChhZXMoeD1yb2kseT1jb250cmFzdCkscG9zaXRpb249cG9zaXRpb25fbnVkZ2UoeCA9IC4xLCB5ID0gMCksb3V0bGllci5zaGFwZSA9IE5BLCBhbHBoYSA9IC41LCB3aWR0aCA9IC4xLCBjb2xvdXIgPSAiYmxhY2siKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IHJvaV9zdW0gJT4lIGZpbHRlcihuZXR3b3JrID09ICJ0b20iKSwgYWVzKHggPSByb2ksIHkgPSBjb250cmFzdCksIHBvc2l0aW9uID0gcG9zaXRpb25fbnVkZ2UoLjMpLCBjb2xvdXIgPSAiQkxBQ0siKSsKICBnZW9tX2Vycm9yYmFyKGRhdGEgPSByb2lfc3VtICU+JSBmaWx0ZXIobmV0d29yayA9PSAidG9tIiksIGFlcyh4PXJvaSx5PWNvbnRyYXN0LCB5bWluID0gY29udHJhc3QtY2ksIHltYXggPSBjb250cmFzdCtjaSksIHBvc2l0aW9uPXBvc2l0aW9uX251ZGdlKHggPSAuMywgeSA9IDApLCB3aWR0aCA9IC4wNSkrCiAgI3RoZW1lX2NsYXNzaWMoKSArIAogIHlsYWIocGFzdGUoImNvbnRyYXN0IGVzdGltYXRlcyAobWVudGFsID4gcGFpbikiKSkgKyAKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkJsdWVzIikgKwogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJCbHVlcyIpICsgCiAgZ2d0aXRsZShwYXN0ZSgiVGhlb3J5LW9mLU1pbmQgbmV0d29yayBjb250cmFzdHMgZXN0aW1hdGVzIGFjcm9zcyBkYXRhc2V0cyBhbmQgcmVnaW9ucyIpKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsKICBmYWNldF93cmFwKH5kYXRhc2V0KSAKRlMyCgpnZ3NhdmUoIlMyLlRJRkYiLCBwbG90ID0gRlMyLCB3aWR0aCA9IDI0LjcsIGhlaWdodCA9IDE1LjI0LCB1bml0cyA9ICJjbSIsIGRwaSA9IDMwMCkKYGBgCgpQbG90IHRoZSBUb00gYWN0aXZpdHkgYWNyb3NzIHJlZ2lvbnMgKEZpZ3VyZSAxQyk6CmBgYHtyfQpzb3VyY2UoIlJfcmFpbmNsb3Vkcy5SIikgIy9Wb2x1bWVzL1Byb2plY3QwMjU1L2NvZGUKc291cmNlKCJzdW1tYXJ5U0UuUiIpCnRoZW1lX3NldCh0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDE1KSkgCgpyb2lfc3VtIDwtIHN1bW1hcnlTRXdpdGhpbihERi5yb2ksIG1lYXN1cmV2YXI9ImNvbnRyYXN0Iiwgd2l0aGludmFycz0gYygicm9pIiwibmV0d29yayIpLCBpZHZhcj0ic3ViIikKCkYxQyA8LSBERi5yb2kgJT4lCiAgZmlsdGVyKG5ldHdvcmsgPT0gInRvbSIpICU+JQogIGdncGxvdCguLGFlcyh4PXJvaSx5PWNvbnRyYXN0LGZpbGw9cm9pKSkrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAiZ3JleSIsIGxpbmV0eXBlID0gMikgKwogIGdlb21fZmxhdF92aW9saW4ocG9zaXRpb249cG9zaXRpb25fbnVkZ2UoeCA9IC4yLCB5ID0gMCksYWRqdXN0ID0yLCB0cmltID0gRkFMU0UsIGNvbG91ciA9ICJCbGFjayIpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSByb2ksIGZpbGwgPSByb2kpLCBwb3NpdGlvbj1wb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAuMDUpLCBzaXplID0gLjUsIHNoYXBlID0gMjEsIGNvbG91ciA9ICJCbGFjayIpICsKICBnZW9tX2JveHBsb3QoYWVzKHg9cm9pLHk9Y29udHJhc3QpLHBvc2l0aW9uPXBvc2l0aW9uX251ZGdlKHggPSAuMSwgeSA9IDApLG91dGxpZXIuc2hhcGUgPSBOQSwgYWxwaGEgPSAuNSwgd2lkdGggPSAuMSwgY29sb3VyID0gImJsYWNrIikgKyAKICBnZW9tX3BvaW50KGRhdGEgPSByb2lfc3VtICU+JSBmaWx0ZXIobmV0d29yayA9PSAidG9tIiksIGFlcyh4ID0gcm9pLCB5ID0gY29udHJhc3QpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX251ZGdlKC4zKSwgY29sb3VyID0gIkJMQUNLIikrCiAgZ2VvbV9lcnJvcmJhcihkYXRhID0gcm9pX3N1bSAlPiUgZmlsdGVyKG5ldHdvcmsgPT0gInRvbSIpLCBhZXMoeD1yb2kseT1jb250cmFzdCwgeW1pbiA9IGNvbnRyYXN0LWNpLCB5bWF4ID0gY29udHJhc3QrY2kpLCBwb3NpdGlvbj1wb3NpdGlvbl9udWRnZSh4ID0gLjMsIHkgPSAwKSwgd2lkdGggPSAuMDUpKwogICN0aGVtZV9jbGFzc2ljKCkgKyAKICB5bGFiKHBhc3RlKCJUaGVvcnktb2YtTWluZCBuZXR3b3JrIGFjdGl2YXRpb24iKSkgKyAKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkJsdWVzIikgKwogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJCbHVlcyIpICsgCiAgI2dndGl0bGUocGFzdGUoIlRoZW9yeS1vZi1NaW5kIG5ldHdvcmsgY29udHJhc3RzIGVzdGltYXRlcyBhY3Jvc3MgZGF0YXNldHMgYW5kIHJlZ2lvbnMiKSkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSAKCkYxQwoKZ2dzYXZlKCJGMUMuVElGRiIsIHBsb3QgPSBGMUMsIHdpZHRoID0gMjQuNywgaGVpZ2h0ID0gMTUuMjQsIHVuaXRzID0gImNtIiwgZHBpID0gMzAwKQpgYGAKCiMjIDYuMyBEaWZmZXJlbmNlcyBpbiBUb00gYWN0aXZhdGlvbiBiZXR3ZWVuIGRhdGFzZXRzOgpUZXN0IGlmIGZvciBwb3RlbnRpYWwgZGlmZmVyZW5jZXMgYmV0d2VlbiBkYXRhc2V0cyBhbmQgcm9pczoKYGBge3J9CmxpYnJhcnkoYnJtcykKdG9tLmNvbXBhcmUgPC0gYnJtKAogIGZvcm11bGEgPSBjb250cmFzdCB+IHJvaSAqIGRhdGFzZXQsCiAgZGF0YSA9IERGLnJvaSAlPiUgZmlsdGVyKG5ldHdvcmsgPT0gInRvbSIpLAogICNmYW1pbHkgID0gY3VtdWxhdGl2ZSgibG9naXQiKSwKICBmaWxlID0gJ3RvbS5jb21wYXJlLlJEUycKKSAKCnN1bW1hcnkodG9tLmNvbXBhcmUpCnBsb3QodG9tLmNvbXBhcmUpCnAgPC0gY29uZGl0aW9uYWxfZWZmZWN0cyh0b20uY29tcGFyZSkKcCA8LSBwWzFdCmdnc2F2ZSgiUzUuVElGRiIsIHBsb3QgPSBwICwgd2lkdGggPSAyNC43LCBoZWlnaHQgPSAxNS4yNCwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDApCgpgYGAKCmBgYHtyfQojIGxvYWQgcmVxdWlyZWQgcGFja2FnZXMKbGlicmFyeShzalBsb3QpCmxpYnJhcnkoaW5zaWdodCkKbGlicmFyeShodHRyKQoKdGFiX21vZGVsKAogIHRvbS5jb21wYXJlLAogIHNob3cuc2UgPSBGQUxTRSwKICAjY29sbGFwc2Uuc2UgPSBUUlVFLAogICNwcmVkLmxhYmVscyA9IGMoIkludGVyY2VwdCIsICJsaW5lYXIgcHJlZGljdG9yIiwgInF1YWRyYXRpYyBwcmVkaWN0b3IiKSwKICAjZHYubGFiZWxzID0gYygiY3VtdWxhdGl2ZSBvcmRpbmFsIG1vZGVsIiwgImN1bXVsYXRpdmUgb3JkaW5hbCBtb2RlbCAoZXhjbHVkaW5nIDE2IHBhcnRpY2lwYW50cykiKSwKICBzaG93Lm9icz1GQUxTRQopCmBgYAoKCiMjIDYuNCBQYWluIE1hdHJpeCBhY3RpdmF0aW9uIGFjcm9zcyBkYXRhc2V0cwpQbG90IHRoZSBQYWluIE1hdHJpeCBhY3Rpdml0eSBhY3Jvc3MgcmVnaW9ucyBhbmQgZGF0YXNldHMgKEZpZ3VyZSBTMyk6CmBgYHtyfQpGUzMgPC0gREYucm9pICU+JQogIGZpbHRlcihuZXR3b3JrID09ICJwYWluIikgJT4lCiAgZ2dwbG90KC4sYWVzKHg9cm9pLHk9Y29udHJhc3QsZmlsbD1yb2kpKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJncmV5IiwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV9mbGF0X3Zpb2xpbihwb3NpdGlvbj1wb3NpdGlvbl9udWRnZSh4ID0gLjIsIHkgPSAwKSxhZGp1c3QgPTIsIHRyaW0gPSBGQUxTRSwgY29sb3VyID0gIkJsYWNrIikgKwogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IHJvaSwgZmlsbCA9IHJvaSksIHBvc2l0aW9uPXBvc2l0aW9uX2ppdHRlcih3aWR0aCA9IC4wNSksIHNpemUgPSAuNSwgc2hhcGUgPSAyMSwgY29sb3VyID0gIkJsYWNrIikgKwogIGdlb21fYm94cGxvdChhZXMoeD1yb2kseT1jb250cmFzdCkscG9zaXRpb249cG9zaXRpb25fbnVkZ2UoeCA9IC4xLCB5ID0gMCksb3V0bGllci5zaGFwZSA9IE5BLCBhbHBoYSA9IC41LCB3aWR0aCA9IC4xLCBjb2xvdXIgPSAiYmxhY2siKSArCiAgZ2VvbV9wb2ludChkYXRhID0gcm9pX3N1bSAlPiUgZmlsdGVyKG5ldHdvcmsgPT0gInBhaW4iKSwgYWVzKHggPSByb2ksIHkgPSBjb250cmFzdCksIHBvc2l0aW9uID0gcG9zaXRpb25fbnVkZ2UoLjMpLCBjb2xvdXIgPSAiQkxBQ0siKSsKICBnZW9tX2Vycm9yYmFyKGRhdGEgPSByb2lfc3VtICU+JSBmaWx0ZXIobmV0d29yayA9PSAicGFpbiIpLCBhZXMoeD1yb2kseT1jb250cmFzdCwgeW1pbiA9IGNvbnRyYXN0LWNpLCB5bWF4ID0gY29udHJhc3QrY2kpLCBwb3NpdGlvbj1wb3NpdGlvbl9udWRnZSh4ID0gLjMsIHkgPSAwKSwgd2lkdGggPSAuMDUpKwogICN0aGVtZV9jbGFzc2ljKCkgKyAKICB5bGFiKHBhc3RlKCJjb250cmFzdCBlc3RpbWF0ZXMgKHBhaW4gPiBtZW50YWwpIikpICsgCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJSZWRzIikgKwogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJSZWRzIikgKyAKICBnZ3RpdGxlKHBhc3RlKCJQYWluIE1hdHJpeCBjb250cmFzdHMgZXN0aW1hdGVzIGFjcm9zcyBkYXRhc2V0cyBhbmQgcmVnaW9ucyIpKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsKICBmYWNldF93cmFwKH5kYXRhc2V0KQpGUzMKZ2dzYXZlKCJTMy5USUZGIiwgcGxvdCA9IEZTMywgd2lkdGggPSAyNC43LCBoZWlnaHQgPSAxNS4yNCwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDApCmBgYAoKIyMgNi41IERpZmZlcmVuY2VzIGluIFBhaW4gTWF0cml4IGFjdGl2YXRpb24gYmV0d2VlbiBkYXRhc2V0czoKVGVzdCBpZiBmb3IgcG90ZW50aWFsIGRpZmZlcmVuY2VzIGJldHdlZW4gZGF0YXNldHMgYW5kIHJvaXM6CmBgYHtyfQpwYWluLmNvbXBhcmUgPC0gYnJtKAogIGZvcm11bGEgPSBjb250cmFzdCB+IHJvaSAqIGRhdGFzZXQsCiAgZGF0YSA9IERGLnJvaSAlPiUgZmlsdGVyKG5ldHdvcmsgPT0gInBhaW4iKSwKICAjZmFtaWx5ICA9IGN1bXVsYXRpdmUoImxvZ2l0IiksCiAgZmlsZSA9ICdwYWluLmNvbXBhcmUuUkRTJwopIAoKc3VtbWFyeShwYWluLmNvbXBhcmUpCnBsb3QocGFpbi5jb21wYXJlKQpjb25kaXRpb25hbF9lZmZlY3RzKHBhaW4uY29tcGFyZSkKYGBgCgpgYGB7cn0KIyBsb2FkIHJlcXVpcmVkIHBhY2thZ2VzCmxpYnJhcnkoc2pQbG90KQpsaWJyYXJ5KGluc2lnaHQpCmxpYnJhcnkoaHR0cikKCnRhYl9tb2RlbCgKICBwYWluLmNvbXBhcmUsCiAgc2hvdy5zZSA9IEZBTFNFLAogICNjb2xsYXBzZS5zZSA9IFRSVUUsCiAgI3ByZWQubGFiZWxzID0gYygiSW50ZXJjZXB0IiwgImxpbmVhciBwcmVkaWN0b3IiLCAicXVhZHJhdGljIHByZWRpY3RvciIpLAogICNkdi5sYWJlbHMgPSBjKCJjdW11bGF0aXZlIG9yZGluYWwgbW9kZWwiLCAiY3VtdWxhdGl2ZSBvcmRpbmFsIG1vZGVsIChleGNsdWRpbmcgMTYgcGFydGljaXBhbnRzKSIpLAogIHNob3cub2JzPUZBTFNFCikKYGBgCgoKIyMgNi42IENvbWJpbmUgSURBUSBzY29yZXMgYW5kIFJPSSBkYXRhOgpDcmVhdGUgb25lIERGOgpgYGB7cn0KREYucm9pIDwtIERGLmlkYXEgJT4lIAogIGdyb3VwX2J5KHN1YixkYXRhc2V0LCBzY2FsZSkgJT4lCiAgdW5ncm91cCgpICU+JSAKICBsZWZ0X2pvaW4oREYucm9pLCBERi5pZGFxLCBieSA9IGMoInN1YiIsImRhdGFzZXQiKSwga2VlcCA9IEZBTFNFKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tPXNjYWxlLCB2YWx1ZXNfZnJvbSA9IHNjb3JlKSAjCmBgYAoKQ2VudGVyIHRoZSB2YXJpYWJsZXMgZm9yIHRoZSBmb3JtYWwgYW5hbHlzaXM6CmBgYHtyfQpERi5yb2kkY2VudF9JREFRTkEgPC0gc2NhbGUoREYucm9pJElEQVFOQSwgc2NhbGUgPSBUUlVFKQpERi5yb2kkY2VudF9JREFRIDwtIHNjYWxlKERGLnJvaSRJREFRLCBzY2FsZSA9IFRSVUUpCkRGLnJvaSA8LSBERi5yb2kgJT4lIGdyb3VwX2J5KHJvaSkgJT4lIG11dGF0ZShjZW50X2NvbnRyYXN0ID0gc2NhbGUoY29udHJhc3QsIHNjYWxlID1UUlVFKSkgI3NjYWxlIHBlciByb2kgKGFuYWx5c2VzIGFyZSBkb25lIHBlciByb2kpCmBgYAoKIyA3LiBJREFRIHNjb3JlcyBhbmQgVG9NIGFjdGl2aXR5IHsudGFic2V0fQoKIyMgNy4xIFBsb3QgVG9NIGFuZCBJREFRCkNyZWF0ZSBzY2F0dGVycGxvdHMgd2l0aCBsaW5lYXIgYW5kIG5vbi1saW5lYXIgbGluZXMgZm9yIFRvTSBuZXR3b3JrOiAKYGBge3J9CmxpYnJhcnkocGF0Y2h3b3JrKQp0aGVtZV9zZXQodGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxNSkpIAoKRjFEIDwtIERGLnJvaSAlPiUKICBmaWx0ZXIobmV0d29yayA9PSAidG9tIikgJT4lCiAgZ2dwbG90KGFlcyh4PWNlbnRfSURBUSwgeT1jZW50X2NvbnRyYXN0KSkgKwogIGdlb21fcG9pbnQoYWxwaGE9MC41LHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIiwgZm9ybXVsYT15IH4geCwgc2U9VFJVRSwgc2hvdy5sZWdlbmQgPSBGQUxTRSwgY29sb3VyPSIjMDA3MkIyIikgKwogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iLCBmb3JtdWxhPXkgfiB4KyBJKHheMiksIHNlPVRSVUUsIHNob3cubGVnZW5kPUZBTFNFLCBjb2xvdXIgPSAiI0Q1NUUwMCIpICsKICBjb29yZF9maXhlZChyYXRpbyA9IDEvMSkgKwogIGxhYnMoCiAgICB4PSJEaXNwb3NpdGlvbmFsIGFudGhyb3BvbW9ycGhpc20iLAogICAgeT0iVGhlb3J5LW9mLU1pbmQgbmV0d29yayBhY3RpdmF0aW9uIgogICkgIysgdGhlbWVfY2xhc3NpYygpCgpGMUQgCgpnZ3NhdmUoIkYxRC5USUZGIiwgcGxvdCA9IEYxRCwgd2lkdGggPSAyNC43LCBoZWlnaHQgPSAxNS4yNCwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDApCmBgYAoKQ3JlYXRlIHNjYXR0ZXJwbG90cyB3aXRoIGxpbmVhciBhbmQgbm9uLWxpbmVhciBsaW5lcyBmb3IgaW5kaXZpZHVhbCByZWdpb25zIG9mIFRvTSBuZXR3b3JrOiAKYGBge3J9CkYxRSA8LSBERi5yb2kgJT4lCiAgZmlsdGVyKG5ldHdvcmsgPT0gInRvbSIpICU+JQogIGdncGxvdChhZXMoeD1jZW50X0lEQVEsIHk9Y2VudF9jb250cmFzdCkpICsKICBnZW9tX3BvaW50KGFscGhhPTAuNSxzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIsIGZvcm11bGE9eSB+IHgsIHNlPVRSVUUsIHNob3cubGVnZW5kID0gRkFMU0UsIGNvbG91cj0iIzAwNzJCMiIpICsKICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIiwgZm9ybXVsYT15IH4geCsgSSh4XjIpLCBzZT1UUlVFLCBzaG93LmxlZ2VuZD1GQUxTRSwgY29sb3VyID0gIiNENTVFMDAiKSArCiAgY29vcmRfZml4ZWQocmF0aW8gPSAxLzEpICsKICBmYWNldF93cmFwKH5yb2ksIG5jb2wgPSA2KSArCiAgbGFicygKICAgIHg9IkRpc3Bvc2l0aW9uYWwgYW50aHJvcG9tb3JwaGlzbSIsCiAgICB5PSJUaGVvcnktb2YtTWluZCBuZXR3b3JrIGFjdGl2YXRpb24iCiAgKSArIHRoZW1lX2NsYXNzaWMoKSAKCkYxRQoKZ2dzYXZlKCJGMUUuVElGRiIsIHBsb3QgPSBGMUUsIHdpZHRoID0gMjQuNywgaGVpZ2h0ID0gMTUuMjQsIHVuaXRzID0gImNtIiwgZHBpID0gMzAwKQoKYGBgCgoKIyMgNy4yIENyZWF0ZSBhIGZ1bmN0aW9uIGZvciB0aGUgQmF5ZXNpYW4gcmVncmVzc2lvbiBtb2RlbHM6CgpGb3IgdGhlIGZvcm1hbCBhbmFseXNpcyB3ZSB3aWxsIHRlc3QgYSBsaW5lYXIgYW5kIHF1YWRyYXRpYyByZWxhdGlvbnNoaXAgYmV0d2VlbiBJREFRIGFuZCBUb00gbmV0d29yayBhY3Rpdml0eToKYGBge3J9CkRGLnJvaSRjZW50X0lEQVEyIDwtIERGLnJvaSRjZW50X0lEQVFeMgpgYGAKCldlIHJ1biB0aGUgbW9kZWxzIHdpdGggdW5pbmZvcm1hdGl2ZSAoZGVmYXVsdCkgcHJpb3JzIGFuZCBjcmVhdGUgYSBmdW5jdGlvbiB0byBydW4gaXQgZm9yIGVhY2ggcmVnaW9uIHNlcGFyYXRlbHk6CmBgYHtyfQpyZWdfbW9kZWwgPC0gZnVuY3Rpb24ocmVnaW9uKXsKICBicm0oZm9ybXVsYSA9IGNlbnRfY29udHJhc3QgfiBjZW50X0lEQVEgKyBjZW50X0lEQVEyLAogICAgICBkYXRhID0gREYucm9pICU+JSBmaWx0ZXIocm9pID09IHJlZ2lvbiksCiAgICAgIGZhbWlseSA9IGdhdXNzaWFuLAogICAgICBjaGFpbnMgPSA0LAogICAgICBpdGVyID0gNDAwMCwKICAgICAgc2VlZCA9IDQyLCAjc28gdGhlIG1vZGVsIGlzIHJlcHJvZHVjaWJsZQogICAgICBmaWxlID0gcGFzdGUwKHJlZ2lvbiwgIi5SRFMiKSkKfQpgYGAKCiMjIDcuMyBSdW4gdGhlIFRvTSByZWdyZXNzaW9uIG1vZGVsczoKUnVuIHRoZSBtb2RlbHMgZm9yIHRoZSBUb00gbmV0d29yayBmaXJzdC4gSXQgd2lsbCBsb2FkIHRoZSBtb2RlbCBpZiBpdCBpcyBhbHJlYWR5IGNhbGN1bGF0ZWQ6CmBgYHtyfQpsaWJyYXJ5KCJicm1zIikKcnRwaiA8LSByZWdfbW9kZWwoInJ0cGoiKQpsdHBqIDwtIHJlZ19tb2RlbCgibHRwaiIpCnByZWMgPC0gcmVnX21vZGVsKCJwcmVjIikKdm1wZmMgPC0gcmVnX21vZGVsKCJ2bXBmYyIpCm1tcGZjIDwtIHJlZ19tb2RlbCgibW1wZmMiKQpkbXBmYyA8LSByZWdfbW9kZWwoImRtcGZjIikKYGBgCgpHZXQgdGhlIHN1bW1hcmllcyAodmVyYmF0aW0sIHJ1biBpbmRpdmlkdWFsbHkpOgpgYGB7cn0Kc3VtbWFyeShydHBqKQpzdW1tYXJ5KGx0cGopCnN1bW1hcnkocHJlYykKc3VtbWFyeSh2bXBmYykKc3VtbWFyeShtbXBmYykKc3VtbWFyeShkbXBmYykKYGBgCgojIyA3LjQgVG9NIG1vZGVsIG91dHB1dDoKVXNlIHNqUGxvdCB0byBjcmVhdGUgaHRtbCB0YWJsZXMgZm9sbG93aW5nIFtwcm9jZWR1cmUgb3V0bGluZWQgaGVyZV0oaHR0cHM6Ly9zdHJlbmdlamFja2UuZ2l0aHViLmlvL3NqUGxvdC9hcnRpY2xlcy90YWJfYmF5ZXMuaHRtbCk6CmBgYHtyfQojIGxvYWQgcmVxdWlyZWQgcGFja2FnZXMKbGlicmFyeShzalBsb3QpCmxpYnJhcnkoaW5zaWdodCkKbGlicmFyeShodHRyKQoKdGFiX21vZGVsKAogIHJ0cGosbHRwaixwcmVjLHZtcGZjLG1tcGZjLGRtcGZjLAogIHNob3cuc2UgPSBUUlVFLAogICNjb2xsYXBzZS5zZSA9IFRSVUUsCiAgcHJlZC5sYWJlbHMgPSBjKCJJbnRlcmNlcHQiLCAibGluZWFyIHByZWRpY3RvciIsICJxdWFkcmF0aWMgcHJlZGljdG9yIiksCiAgZHYubGFiZWxzID0gYygicnRwaiIsICJsdHBqIiwicHJlYyIsInZtcGZjIiwibW1wZmMiLCJkbXBmYyIpLAogIHNob3cub2JzPUZBTFNFCikKYGBgCgojIyA3LjUgUG9zdGVyaW9yIHBsb3RzOgpDcmVhdGUgcGxvdHMgYmFzZWQgb24gW3RoaXMgdHV0b3JpYWxdKGh0dHBzOi8vd3d3LnJlbnN2YW5kZXNjaG9vdC5jb20vdHV0b3JpYWxzL3ItbGluZWFyLXJlZ3Jlc3Npb24tYmF5ZXNpYW4tdXNpbmctYnJtcy8pOgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCnRvbV9jb21iaW5lZCA8LSBiaW5kX3Jvd3MoInJ0cGoiID0gYXNfdGliYmxlKGFzLm1jbWMocnRwaiwgIHBhcnMgPSBjKCJiX2NlbnRfSURBUSIsICJiX2NlbnRfSURBUTIiKSwgY29tYmluZV9jaGFpbnMgPSBUUlVFKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgImx0cGoiID0gYXNfdGliYmxlKGFzLm1jbWMobHRwaiwgcGFycyA9IGMoImJfY2VudF9JREFRIiwgImJfY2VudF9JREFRMiIpLGNvbWJpbmVfY2hhaW5zID0gVFJVRSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICJwcmVjIiA9IGFzX3RpYmJsZShhcy5tY21jKHByZWMsIHBhcnMgPSBjKCJiX2NlbnRfSURBUSIsICJiX2NlbnRfSURBUTIiKSxjb21iaW5lX2NoYWlucyA9IFRSVUUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAidm1wZmMiID0gYXNfdGliYmxlKGFzLm1jbWModm1wZmMsIHBhcnMgPSBjKCJiX2NlbnRfSURBUSIsICJiX2NlbnRfSURBUTIiKSxjb21iaW5lX2NoYWlucyA9IFRSVUUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAibW1wZmMiID0gYXNfdGliYmxlKGFzLm1jbWMobW1wZmMsIHBhcnMgPSBjKCJiX2NlbnRfSURBUSIsICJiX2NlbnRfSURBUTIiKSxjb21iaW5lX2NoYWlucyA9IFRSVUUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAiZG1wZmMiID0gYXNfdGliYmxlKGFzLm1jbWMoZG1wZmMsIHBhcnMgPSBjKCJiX2NlbnRfSURBUSIsICJiX2NlbnRfSURBUTIiKSxjb21iaW5lX2NoYWlucyA9IFRSVUUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAuaWQgPSAicm9pIikKCm9yZGVyIDwtIGMoInJ0cGoiLCAibHRwaiIsICJwcmVjIiwgInZtcGZjIiwibW1wZmMiLCJkbXBmYyIsICJyczIiLCAibHMyIiwgInJpbnN1bGEiLCAibGluc3VsYSIsICJybWZnIiwgImxtZmciLCAiYW1jYyIpICAKCnRvbV9jb21iaW5lZCA8LSB0b21fY29tYmluZWQgJT4lCiAgcmVuYW1lKGxpbmVhciA9IGJfY2VudF9JREFRLCBxdWFkcmF0aWMgPSBiX2NlbnRfSURBUTIpICU+JQogIHBpdm90X2xvbmdlcihjKCJsaW5lYXIiLCAicXVhZHJhdGljIiksbmFtZXNfdG8gPSAidmFySURBUSIpICU+JQogIG11dGF0ZShyb2kgPSBmY3RfcmVsZXZlbChyb2ksIG9yZGVyWzE6Nl0pKQpgYGAKClBsb3QgdGhlIGRpc3RyaWJ1dGlvbnM6CmBgYHtyfQpGMiA8LSB0b21fY29tYmluZWQgJT4lCiAgbXV0YXRlX2F0KHZhcnMoLXZhbHVlKSxhcy5mYWN0b3IpICU+JQogIHJlbmFtZShwcmVkaWN0b3IgPSB2YXJJREFRKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHZhbHVlLCBmaWxsID0gcHJlZGljdG9yKSkgKwogIGdlb21fZGVuc2l0eShhbHBoYSA9IC41KSsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJibGFjayIsIGxpbmV0eXBlID0gMikgKwogIGdndGl0bGUocGFzdGUoIlBvc3RlcmlvciBkaXN0cmlidXRpb25zIGZvciB0aGUgVGhlb3J5LW9mLU1pbmQgbmV0d29yayIpKSArIAogIGZhY2V0X3dyYXAofnJvaSwgbmNvbCA9MSkgKwogIGNvb3JkX2ZpeGVkKHJhdGlvID0gMS80MCkgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gOCkgKwogIHRoZW1lKHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiIzAwNzJCMiIsICIjRDU1RTAwIikpKyAKICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSkKRjIKCmdnc2F2ZSgiRjIuVElGRiIsIHBsb3QgPSBGMiwgd2lkdGggPSAyNC43LCBoZWlnaHQgPSAxNS4yNCwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDApCmBgYAoKIyA4LiBJREFRIHNjb3JlcyBhbmQgUGFpbiBNYXRyaXggYWN0aXZpdHkgey50YWJzZXR9CgojIyA4LjEgUGxvdCBQYWluIE1hdHJpeCBhbmQgSURBUQpDcmVhdGUgc2NhdHRlcnBsb3RzIHdpdGggbGluZWFyIGFuZCBub24tbGluZWFyIGxpbmVzIGZvciB0aGUgUGFpbiBNYXRyaXg6IApgYGB7cn0KUzQgPC0gREYucm9pICU+JQogIGZpbHRlcihuZXR3b3JrID09ICJwYWluIikgJT4lCiAgZ2dwbG90KGFlcyh4PWNlbnRfSURBUSwgeT1jZW50X2NvbnRyYXN0KSkgKwogIGdlb21fcG9pbnQoYWxwaGE9MC41LHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIiwgZm9ybXVsYT15IH4geCwgc2U9VFJVRSwgc2hvdy5sZWdlbmQgPSBGQUxTRSwgY29sb3VyPSIjMDA3MkIyIikgKwogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iLCBmb3JtdWxhPXkgfiB4KyBJKHheMiksIHNlPVRSVUUsIHNob3cubGVnZW5kPUZBTFNFLCBjb2xvdXIgPSAiI0Q1NUUwMCIpICsKICAjY29vcmRfZml4ZWQocmF0aW8gPSAyNS8xKSArCiAgbGFicygKICAgIHg9IklEQVEgc2NvcmUiLAogICAgeT0iY29udHJhc3QgKHBhaW4gdnMgbWVudGFsKSIKICApICsgdGhlbWVfY2xhc3NpYygpCgpTNCAKCmdnc2F2ZSgiUzQuVElGRiIsIHBsb3QgPSBTNCwgd2lkdGggPSAyNC43LCBoZWlnaHQgPSAxNS4yNCwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDApCmBgYAoKQ3JlYXRlIHNjYXR0ZXJwbG90cyB3aXRoIGxpbmVhciBhbmQgbm9uLWxpbmVhciBsaW5lcyBmb3IgaW5kaXZpZHVhbCByZWdpb25zIG9mIHRoZSBQYWluIE1hdHJpeDogCmBgYHtyfQpTNSA8LSBERi5yb2kgJT4lCiAgZmlsdGVyKG5ldHdvcmsgPT0gInBhaW4iKSAlPiUKICBnZ3Bsb3QoYWVzKHg9Y2VudF9JREFRLCB5PWNlbnRfY29udHJhc3QpKSArCiAgZ2VvbV9wb2ludChhbHBoYT0wLjUsc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iLCBmb3JtdWxhPXkgfiB4LCBzZT1UUlVFLCBzaG93LmxlZ2VuZCA9IEZBTFNFLCBjb2xvdXI9IiMwMDcyQjIiKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIsIGZvcm11bGE9eSB+IHgrIEkoeF4yKSwgc2U9VFJVRSwgc2hvdy5sZWdlbmQ9RkFMU0UsIGNvbG91ciA9ICIjRDU1RTAwIikgKwogICNjb29yZF9maXhlZChyYXRpbyA9IDI1LzEpICsKICBsYWJzKAogICAgeD0iSURBUSBzY29yZSIsCiAgICB5PSJjb250cmFzdCAocGFpbiB2cyBtZW50YWwpIgogICkgKyB0aGVtZV9jbGFzc2ljKCkgKwogIGZhY2V0X3dyYXAofnJvaSwgbnJvdyA9IDIpCgpTNSAKCmdnc2F2ZSgiUzUuVElGRiIsIHBsb3QgPSBTNSwgd2lkdGggPSAyNC43LCBoZWlnaHQgPSAxNS4yNCwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDApCmBgYAoKCiMjIDguMiBSZWdyZXNzaW9uIG1vZGVscyBmb3IgdGhlIFBhaW4gTWF0cml4OgpSdW4gdGhlIG1vZGVscyBmb3IgdGhlIFBhaW4gTWF0cml4IChjb250cm9sIG5ldHdvcmspLiBJdCB3aWxsIGxvYWQgdGhlIG1vZGVsIGlmIGl0IGlzIGFscmVhZHkgY2FsY3VsYXRlZDoKYGBge3J9CnJzMiA8LSByZWdfbW9kZWwoInJzMiIpCmxzMiA8LSByZWdfbW9kZWwoImxzMiIpCnJpbnN1bGEgPC0gcmVnX21vZGVsKCJyaW5zdWxhIikKbGluc3VsYSA8LSByZWdfbW9kZWwoImxpbnN1bGEiKQpybWZnIDwtIHJlZ19tb2RlbCgicm1mZyIpCmxtZmcgPC0gcmVnX21vZGVsKCJsbWZnIikKYW1jYyA8LSByZWdfbW9kZWwoImFtY2MiKQpgYGAKCkdldCB0aGUgc3VtbWFyaWVzICh2ZXJiYXRpbSwgcnVuIGluZGl2aWR1YWxseSk6CmBgYHtyfQpzdW1tYXJ5KHJzMikKc3VtbWFyeShsczIpCnN1bW1hcnkocmluc3VsYSkKc3VtbWFyeShsaW5zdWxhKQpzdW1tYXJ5KHJtZmcpCnN1bW1hcnkobG1mZykKc3VtbWFyeShhbWNjKQpgYGAKCiMjIDguMyBQYWluIE1hdHJpeCBtb2RlbCBvdXRwdXQ6ClVzZSBzalBsb3QgdG8gY3JlYXRlIGh0bWwgdGFibGVzIGZvbGxvd2luZyBbcHJvY2VkdXJlIG91dGxpbmVkIGhlcmVdKGh0dHBzOi8vc3RyZW5nZWphY2tlLmdpdGh1Yi5pby9zalBsb3QvYXJ0aWNsZXMvdGFiX2JheWVzLmh0bWwpOgpgYGB7cn0KdGFiX21vZGVsKAogIHJzMixsczIscmluc3VsYSxsaW5zdWxhLHJtZmcsbG1mZyxhbWNjLAogIHNob3cuc2UgPSBUUlVFLAogICNjb2xsYXBzZS5zZSA9IFRSVUUsCiAgcHJlZC5sYWJlbHMgPSBjKCJJbnRlcmNlcHQiLCAibGluZWFyIHByZWRpY3RvciIsICJxdWFkcmF0aWMgcHJlZGljdG9yIiksCiAgZHYubGFiZWxzID0gYygicnMyIiwibHMyIiwicmluc3VsYSIsImxpbnN1bGEiLCJybWZnIiwibG1mZyIsImFtY2MiKSwKICBzaG93Lm9icz1GQUxTRQopCmBgYAoKIyMgOC40IFBvc3RlcmlvciBwbG90czoKQ3JlYXRlIHBsb3RzIGJhc2VkIG9uIFt0aGlzIHR1dG9yaWFsXShodHRwczovL3d3dy5yZW5zdmFuZGVzY2hvb3QuY29tL3R1dG9yaWFscy9yLWxpbmVhci1yZWdyZXNzaW9uLWJheWVzaWFuLXVzaW5nLWJybXMvKToKYGBge3J9CnBhaW5fY29tYmluZWQgPC0gYmluZF9yb3dzKCJyczIiID0gYXNfdGliYmxlKGFzLm1jbWMocnMyLCAgcGFycyA9IGMoImJfY2VudF9JREFRIiwgImJfY2VudF9JREFRMiIpLCBjb21iaW5lX2NoYWlucyA9IFRSVUUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAibHMyIiA9IGFzX3RpYmJsZShhcy5tY21jKGxzMiwgcGFycyA9IGMoImJfY2VudF9JREFRIiwgImJfY2VudF9JREFRMiIpLGNvbWJpbmVfY2hhaW5zID0gVFJVRSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICJyaW5zdWxhIiA9IGFzX3RpYmJsZShhcy5tY21jKHJpbnN1bGEsIHBhcnMgPSBjKCJiX2NlbnRfSURBUSIsICJiX2NlbnRfSURBUTIiKSxjb21iaW5lX2NoYWlucyA9IFRSVUUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAibGluc3VsYSIgPSBhc190aWJibGUoYXMubWNtYyhsaW5zdWxhLCBwYXJzID0gYygiYl9jZW50X0lEQVEiLCAiYl9jZW50X0lEQVEyIiksY29tYmluZV9jaGFpbnMgPSBUUlVFKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgInJtZmciID0gYXNfdGliYmxlKGFzLm1jbWMocm1mZywgcGFycyA9IGMoImJfY2VudF9JREFRIiwgImJfY2VudF9JREFRMiIpLGNvbWJpbmVfY2hhaW5zID0gVFJVRSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICJsbWZnIiA9IGFzX3RpYmJsZShhcy5tY21jKGxtZmcsIHBhcnMgPSBjKCJiX2NlbnRfSURBUSIsICJiX2NlbnRfSURBUTIiKSxjb21iaW5lX2NoYWlucyA9IFRSVUUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAiYW1jYyIgPSBhc190aWJibGUoYXMubWNtYyhhbWNjLCBwYXJzID0gYygiYl9jZW50X0lEQVEiLCAiYl9jZW50X0lEQVEyIiksY29tYmluZV9jaGFpbnMgPSBUUlVFKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgLmlkID0gInJvaSIpCgpwYWluX2NvbWJpbmVkIDwtIHBhaW5fY29tYmluZWQgJT4lCiAgcmVuYW1lKGxpbmVhciA9IGJfY2VudF9JREFRLCBxdWFkcmF0aWMgPSBiX2NlbnRfSURBUTIpICU+JQogIHBpdm90X2xvbmdlcihjKCJsaW5lYXIiLCAicXVhZHJhdGljIiksbmFtZXNfdG8gPSAidmFySURBUSIpICU+JQogIG11dGF0ZShyb2kgPSBmY3RfcmVsZXZlbChyb2ksIG9yZGVyWzc6MTNdKSkKYGBgCgpQbG90IHRoZSBkaXN0cmlidXRpb25zOgpgYGB7cn0KUzYgPC0gcGFpbl9jb21iaW5lZCAlPiUKICBtdXRhdGVfYXQodmFycygtdmFsdWUpLGFzLmZhY3RvcikgJT4lCiAgcmVuYW1lKHByZWRpY3RvciA9IHZhcklEQVEpICU+JQogIGdncGxvdCguLCBhZXModmFsdWUsIGZpbGwgPSBwcmVkaWN0b3IpKSArCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gLjUpKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGNvbG9yID0gImJsYWNrIiwgbGluZXR5cGUgPSAyKSArCiAgZ2d0aXRsZShwYXN0ZSgiUG9zdGVyaW9yIGRpc3RyaWJ1dGlvbnMgZm9yIHRoZSBQYWluIE1hdHJpeCIpKSArIAogIGZhY2V0X3dyYXAofnJvaSwgbmNvbCA9MSkgKwogIGNvb3JkX2ZpeGVkKHJhdGlvID0gMS80MCkgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gOCkgKwogIHRoZW1lKHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiIzAwNzJCMiIsICIjRDU1RTAwIikpCiN0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSkKClM2IAoKZ2dzYXZlKCJTNi5USUZGIiwgcGxvdCA9IFM2LCB3aWR0aCA9IDI0LjcsIGhlaWdodCA9IDE1LjI0LCB1bml0cyA9ICJjbSIsIGRwaSA9IDMwMCkKYGBgCgoKIyMgOSBPbmUgbW9kZWwgYWNyb3NzIHRoZSBuZXR3b3JrcyAKCiMjIDkuMSBUaGVvcnktb2YtTWluZDoKQWxsIFRvTSByZWdpb25zIGNvbWJpbmVkOgpgYGB7cn0KdG9tIDwtIGJybShmb3JtdWxhID0gY2VudF9jb250cmFzdCB+IGNlbnRfSURBUSArIGNlbnRfSURBUTIsCiAgICAgIGRhdGEgPSBERi5yb2kgJT4lIGZpbHRlcihuZXR3b3JrID09ICJ0b20iKSwKICAgICAgZmFtaWx5ID0gZ2F1c3NpYW4sCiAgICAgIGNoYWlucyA9IDQsCiAgICAgIGl0ZXIgPSA0MDAwLAogICAgICBzZWVkID0gNDIsICNzbyB0aGUgbW9kZWwgaXMgcmVwcm9kdWNpYmxlCiAgICAgIGZpbGUgPSAidG9tLlJEUyIpCmBgYAoKU3VtbWFyeToKYGBge3J9CnN1bW1hcnkodG9tKQpgYGAKCiMjIDkuMiBQYWluIE1hdHJpeDoKQWxsIFRvTSByZWdpb25zIGNvbWJpbmVkOgpgYGB7cn0KcGFpbiA8LSBicm0oZm9ybXVsYSA9IGNlbnRfY29udHJhc3QgfiBjZW50X0lEQVEgKyBjZW50X0lEQVEyLAogICAgICBkYXRhID0gREYucm9pICU+JSBmaWx0ZXIobmV0d29yayA9PSAicGFpbiIpLAogICAgICBmYW1pbHkgPSBnYXVzc2lhbiwKICAgICAgY2hhaW5zID0gNCwKICAgICAgaXRlciA9IDQwMDAsCiAgICAgIHNlZWQgPSA0MiwgI3NvIHRoZSBtb2RlbCBpcyByZXByb2R1Y2libGUKICAgICAgZmlsZSA9ICJwYWluLlJEUyIpCmBgYAoKU3VtbWFyeToKYGBge3J9CnN1bW1hcnkocGFpbikKYGBgCgojIyA5LjMgUG9zdGVyaW9yIHBsb3RzIGZvciB0aGUgdHdvIG5ldHdvcmtzOgoKYGBge3J9CnRhYl9tb2RlbCgKICB0b20sIHBhaW4sCiAgc2hvdy5zZSA9IFRSVUUsCiAgI2NvbGxhcHNlLnNlID0gVFJVRSwKICBwcmVkLmxhYmVscyA9IGMoIkludGVyY2VwdCIsICJsaW5lYXIgcHJlZGljdG9yIiwgInF1YWRyYXRpYyBwcmVkaWN0b3IiKSwKICBkdi5sYWJlbHMgPSBjKCJ0b20iLCJwYWluIiksCiAgc2hvdy5vYnM9RkFMU0UKKQpgYGAKCiMjIDkuNCBQb3N0ZXJpb3IgcGxvdHMgZm9yIHRoZSB0d28gbmV0d29ya3M6CgpgYGB7cn0KdG9tX2FsbCA8LSBiaW5kX3Jvd3MoImFsbCIgPSBhc190aWJibGUoYXMubWNtYyh0b20sICBwYXJzID0gYygiYl9jZW50X0lEQVEiLCAiYl9jZW50X0lEQVEyIiksIGNvbWJpbmVfY2hhaW5zID0gVFJVRSksIC5pZCA9ICJuZXR3b3JrIikgICU+JQogICAgICAgICAgICAgICAgICAgICAgICByZW5hbWUobGluZWFyID0gYl9jZW50X0lEQVEsIHF1YWRyYXRpYyA9IGJfY2VudF9JREFRMikgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgIHBpdm90X2xvbmdlcihjKCJsaW5lYXIiLCAicXVhZHJhdGljIiksbmFtZXNfdG8gPSAidmFySURBUSIpICU+JQogICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUobmV0d29yayA9ICJ0b20iKSkKCnBhaW5fYWxsIDwtIGJpbmRfcm93cygiYWxsIiA9IGFzX3RpYmJsZShhcy5tY21jKHBhaW4sICBwYXJzID0gYygiYl9jZW50X0lEQVEiLCAiYl9jZW50X0lEQVEyIiksIGNvbWJpbmVfY2hhaW5zID0gVFJVRSksIC5pZCA9ICJuZXR3b3JrIikgICU+JQogICAgICAgICAgICAgICAgICAgICAgICByZW5hbWUobGluZWFyID0gYl9jZW50X0lEQVEsIHF1YWRyYXRpYyA9IGJfY2VudF9JREFRMikgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgIHBpdm90X2xvbmdlcihjKCJsaW5lYXIiLCAicXVhZHJhdGljIiksbmFtZXNfdG8gPSAidmFySURBUSIpICU+JQogICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUobmV0d29yayA9ICJwYWluIikpCgp0b21fYWxsICU+JSBiaW5kX3Jvd3MoLiwgcGFpbl9hbGwpICU+JQogIG11dGF0ZV9hdCh2YXJzKC12YWx1ZSksYXMuZmFjdG9yKSAlPiUKICByZW5hbWUocHJlZGljdG9yID0gdmFySURBUSkgJT4lCiAgZ2dwbG90KC4sIGFlcyh2YWx1ZSwgZmlsbCA9IHByZWRpY3RvcikpICsKICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAuNSkrCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAiYmxhY2siLCBsaW5ldHlwZSA9IDIpICsKICBnZ3RpdGxlKHBhc3RlKCJQb3N0ZXJpb3IgZGlzdHJpYnV0aW9ucyBhY3Jvc3MgdGhlIHR3byBuZXR3b3JrcyIpKSArIAogIGZhY2V0X3dyYXAofm5ldHdvcmspICsKICBjb29yZF9maXhlZChyYXRpbyA9IDEvNDApICsKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDE2KSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIiMwMDcyQjIiLCAiI0Q1NUUwMCIpKSsgCiAgdGhlbWUoc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgojIyA5LjUgSERJK1JPUEUgZGVjaXNpb24gcnVsZQoKYGBge3J9CmxpYnJhcnkoImVhc3lzdGF0cyIpCgpoZGlfcm9wZSA8LSBmdW5jdGlvbihtb2RlbCl7CiAgcm9wZSA8LSByb3BlX3JhbmdlKG1vZGVsKQogIHJvcGVfbW9kZWwgPC0gZXF1aXZhbGVuY2VfdGVzdChtb2RlbCwgcmFuZ2UgPSByb3BlLCBjaSA9IDAuOTUpIAogICNyb3BlX21vZGVsICU+JSBtdXRhdGUocm9pID0gYXMuY2hhcmFjdGVyKG1vZGVsJGZpbGUpKQogIHBsb3Qocm9wZV9tb2RlbCkgKyB0aGVtZV9jbGFzc2ljKCkgKyAKICAgIGdndGl0bGUoZGVwYXJzZShzdWJzdGl0dXRlKG1vZGVsKSkpICsgCiAgICB4bGltKC0wLjE1LDAuMTUpICsgIAogICAgdGhlbWUoYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpIAogICAgI3NjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCIjMDA3MkIyIiwgIiNENTVFMDAiKSkKfQoKaGRpX3JvcGUodG9tKSArIGhkaV9yb3BlKHBhaW4pICsgcGxvdF9sYXlvdXQoZ3VpZGVzID0gJ2NvbGxlY3QnKSAgCgoKKGhkaV9yb3BlKHJ0cGopIC8gaGRpX3JvcGUobHRwaikgLyBoZGlfcm9wZShwcmVjKSkgJgooaGRpX3JvcGUodm1wZmMpIC8gaGRpX3JvcGUobW1wZmMpIC8gaGRpX3JvcGUoZG1wZmMpKSArIHBsb3RfbGF5b3V0KGd1aWRlcyA9ICdjb2xsZWN0JykgIAoKKGhkaV9yb3BlKHJ0cGopIHwgaGRpX3JvcGUobHRwaikpIC8KKGhkaV9yb3BlKHByZWMpIHwgaGRpX3JvcGUodm1wZmMpKSAvCihoZGlfcm9wZShtbXBmYykgfCBoZGlfcm9wZShkbXBmYykpICsgcGxvdF9sYXlvdXQoZ3VpZGVzID0gJ2NvbGxlY3QnKSAgCgoKYGBgCgojIDEwLiBDb250cm9sIGFuYWx5c2VzIHsudGFic2V0fQoKIyMxMC4xIFRoZW9yeS1vZi1NaW5kIG5ldHdvcmsKVXBkYXRlIHRoZSBtb2RlbHMgYnkgcmVtb3ZpbmcgdGhlIDE2IHBhcnRpY2lwYW50cyB0aGF0IGNvbXBsZXRlZCBhIGRpZmZlcmVudCB2ZXJzaW9uIG9mIHRoZSBJREFRICgxLTEwKS4gV2UgY3JlYXRlIGEgZnVuY3Rpb24gdG8gZG8gdGhpczoKYGBge3J9Cgp1cGRhdGVfbW9kZWwgPC0gZnVuY3Rpb24obW9kZWxfb2xkLCByZWdpb24pewogIG1vZGVsX25ldyA8LSB1cGRhdGUobW9kZWxfb2xkLCBuZXdkYXRhID0gREYucm9pICU+JSBmaWx0ZXIocm9pID09IHJlZ2lvbiAmICFzdWIgJWluJSBzdWJfZXgpLCBzZWVkID0gNDEpCiAgCiAgbTEgPC0gcG9zdGVyaW9yX3N1bW1hcnkobW9kZWxfb2xkKVtjKCJiX2NlbnRfSURBUSIsICJiX2NlbnRfSURBUTIiKSAsICJFc3RpbWF0ZSJdCiAgbTIgPC0gcG9zdGVyaW9yX3N1bW1hcnkobW9kZWxfbmV3KVtjKCJiX2NlbnRfSURBUSIsICJiX2NlbnRfSURBUTIiKSAsICJFc3RpbWF0ZSJdCiAgCiAgdGliYmxlKGJpYXMgPSByb3VuZCgxMDAqKChtMS1tMikvbTIpLCAyKSwgcHJlZGljdG9yID0gYygiYl9jZW50X0lEQVEiLCAiYl9jZW50X0lEQVEyIikpCn0KYGBgCgpDYWxjdWxhdGUgdGhlIGRpZmZlcmVuY2UgKGJpYXMpIHBlciBUb00gcmVnaW9uOgpgYGB7cn0KcnRwal9iaWFzIDwtIHVwZGF0ZV9tb2RlbChydHBqLCAicnRwaiIpCmx0cGpfYmlhcyA8LSB1cGRhdGVfbW9kZWwobHRwaiwgImx0cGoiKQpwcmVjX2JpYXMgPC0gdXBkYXRlX21vZGVsKHByZWMsICJwcmVjIikKdm1wZmNfYmlhcyA8LSB1cGRhdGVfbW9kZWwodm1wZmMsICJ2bXBmYyIpCm1tcGZjX2JpYXMgPC0gdXBkYXRlX21vZGVsKG1tcGZjLCAibW1wZmMiKQpkbXBmY19iaWFzIDwtIHVwZGF0ZV9tb2RlbChkbXBmYywgImRtcGZjIikKCiMgbG9hZCByZXF1aXJlZCBwYWNrYWdlcwpsaWJyYXJ5KHNqUGxvdCkKbGlicmFyeShpbnNpZ2h0KQpsaWJyYXJ5KGh0dHIpCgp0YWJfbW9kZWwoCiAgcnRwal9iaWFzLAogIHNob3cuc2UgPSBUUlVFLAogICNjb2xsYXBzZS5zZSA9IFRSVUUsCiAgI3ByZWQubGFiZWxzID0gYygiSW50ZXJjZXB0IiwgImxpbmVhciBwcmVkaWN0b3IiLCAicXVhZHJhdGljIHByZWRpY3RvciIpLAogICNkdi5sYWJlbHMgPSBjKCJydHBqIiwgImx0cGoiLCJwcmVjIiwidm1wZmMiLCJtbXBmYyIsImRtcGZjIiksCiAgc2hvdy5vYnM9RkFMU0UKKQpgYGAKCiMjMTAuMSBQYWluIE1hdHJpeApDYWxjdWxhdGUgdGhlIGRpZmZlcmVuY2UgKGJpYXMpIHBlciBQYWluIE1hdHJpeCByZWdpb246CmBgYHtyfQpyczJfYmlhcyA8LSB1cGRhdGVfbW9kZWwocnRwaiwgInJzMiIpCmxzMl9iaWFzIDwtIHVwZGF0ZV9tb2RlbChsdHBqLCAibHMyIikKcmluc3VsYV9iaWFzIDwtIHVwZGF0ZV9tb2RlbChwcmVjLCAicmluc3VsYSIpCmxpbnN1bGFfYmlhcyA8LSB1cGRhdGVfbW9kZWwodm1wZmMsICJsaW5zdWxhIikKcm1mZ19iaWFzIDwtIHVwZGF0ZV9tb2RlbChtbXBmYywgInJtZmciKQpsbWZnX2JpYXMgPC0gdXBkYXRlX21vZGVsKGRtcGZjLCAibG1mZyIpCmFtY2NfYmlhcyA8LSB1cGRhdGVfbW9kZWwoZG1wZmMsICJhbWNjIikKYGBgCgpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGAK